Advertisement IC Markets

Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision

Optimize MetaTrader 4, MetaTrader 5, cTrader, and TradingView for speed. Discuss Level II Market Depth (DOM), custom hotkeys, and volume indicators.
PTScalper
Site Admin
Posts: 1479
Joined: Mon Jul 20, 2026 1:28 pm

Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision

Post by PTScalper »

Most retail scalpers consistently struggle on the 1-minute (M1) chart because they rely on default (14,3,3) Stochastic settings. On an M1 timeframe, a 14-period lookback introduces severe mathematical lag—by the time the %K line crosses %D inside the extreme zones, institutional order flow has already exhausted the immediate directional move. To capture rapid 3-to-5 pip scalps without getting shredded by random market microstructure noise, you must dynamically calibrate your oscillator parameters to the session's underlying volatility regime.1. The Core Parameter SetupsSetup (%K, %D, Slowing)Market RegimeExecution Profile5,3,3Balanced / Default M1Balances fast 5-period momentum tracking with 3-period smoothing to eliminate tick-level whipsaws.9,3,1Strong Intraday TrendsUses a 9-period lookback to prevent premature shakeouts while maintaining a hyper-responsive 1-period trigger line for London/NY continuation entries.5,2,2High Volatility / News DriftMaximizes entry velocity for aggressive scalping on high-beta pairs like GBP/JPY or XAU/USD.2. Dynamic Threshold CalibrationStatic 80/20 boundary zones fail systematically during shifting intraday volatility cycles. To protect your win rate and filter out false breakouts, adjust your overbought and oversold thresholds dynamically based on price action:Trending & High-Volatility Regimes (85/15): Widening the extreme zones prevents you from entering premature counter-trend reversal trades during aggressive liquidity runs and momentum spikes.Ranging & Asian Session Regimes (70/30): Tightening the boundary thresholds allows you to capture higher-frequency mean-reversion swings when price action is tightly bound inside intraday liquidity pools.3. Institutional Confluence & Execution FiltersNever trade mechanical M1 Stochastic crossovers in a vacuum. An oscillator signal is only valid when filtered through higher-timeframe structure and order flow:Trend Baseline Filter: Overlay a 50 EMA or 200 EMA directly on your chart. Only execute oversold buy crossovers when price is trending above the moving average, and restrict overbought sell crossovers to when price is trading below it.Momentum Divergence: Monitor real-time divergence between price action and the %K trajectory. A lower low in price paired with a higher low on a 5,3,3 Stochastic indicates waning selling pressure, providing an institutional footprint for high-probability reversal execution.Always backtest these parameter shifts across at least 50 sample trades per session before deploying live capital. What Stochastic configurations are you guys currently running on M1?To help visualize how parameter sensitivity impacts signal frequency and whipsaw filtering on an M1 price feed, here is an interactive parameter simulator:
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Recommended broker for automated trading & scalping IC Markets
PTScalper
Site Admin
Posts: 1479
Joined: Mon Jul 20, 2026 1:28 pm

Re: Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision

Post by PTScalper »

// MQL4: Directly calculating and fetching the Moving Average for bar 0
double maVal = iMA(NULL, 0, 14, 0, MODE_SMA, PRICE_CLOSE, 0);

// MQL5: Create the indicator handle inside OnInit()
int maHandle = iMA(_Symbol, _Period, 14, 0, MODE_SMA, PRICE_CLOSE);

// MQL5: Retrieve the values inside OnCalculate()
double maBuffer[];
ArraySetAsSeries(maBuffer, true); // Set index 0 to the current bar
CopyBuffer(maHandle, 0, 0, 1, maBuffer);
double maVal = maBuffer[0];
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
FTtrader
Posts: 316
Joined: Mon Aug 03, 2026 2:43 pm

Re: Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision

Post by FTtrader »

PTScalper wrote: Sun Jul 26, 2026 3:27 pm // MQL4: Directly calculating and fetching the Moving Average for bar 0
double maVal = iMA(NULL, 0, 14, 0, MODE_SMA, PRICE_CLOSE, 0);

// MQL5: Create the indicator handle inside OnInit()
int maHandle = iMA(_Symbol, _Period, 14, 0, MODE_SMA, PRICE_CLOSE);

// MQL5: Retrieve the values inside OnCalculate()
double maBuffer[];
ArraySetAsSeries(maBuffer, true); // Set index 0 to the current bar
CopyBuffer(maHandle, 0, 0, 1, maBuffer);
double maVal = maBuffer[0];
Hi PTscalpers,

i played with that code little bit and prepared my own version:

How to use this code:

1.) Open your MT4 terminal.

2.) Press F4 to open the MetaEditor.

3.) Go to File > New > Expert Advisor (template). Name it M1_Stoch_Scalper.

4.) Delete all the default code and paste the code below.

5.) Click Compile (or press F7).

MQL4 version:

Code: Select all

//+------------------------------------------------------------------+
//|                                            M1_Stoch_Scalper.mq4  |
//|                                     Institutional Scalping Logic |
//+------------------------------------------------------------------+
#property copyright "Your Name"
#property link      ""
#property version   "1.00"
#property strict

//+------------------------------------------------------------------+
//| Input Parameters                                                 |
//+------------------------------------------------------------------+
input string   __1__             = "--- Stochastic Settings ---";
input int      InpKPeriod        = 5;      // %K Period (5, 9, or 5)
input int      InpDPeriod        = 3;      // %D Period (3, 3, or 2)
input int      InpSlowing        = 3;      // Slowing (3, 1, or 2)
input int      InpOBLevel        = 80;     // Overbought (85 for Volatility, 70 for Range)
input int      InpOSLevel        = 20;     // Oversold (15 for Volatility, 30 for Range)

input string   __2__             = "--- Trend Filter ---";
input int      InpEMAPeriod      = 50;     // EMA Period (50 or 200)

input string   __3__             = "--- Execution & Risk ---";
input double   InpLotSize        = 0.1;    // Fixed Lot Size
input int      InpTakeProfitPips = 5;      // Take Profit (Pips)
input int      InpStopLossPips   = 3;      // Stop Loss (Pips)
input int      InpSlippage       = 3;      // Max Slippage (Points)
input int      InpMagicNumber    = 98765;  // Magic Number

// Global Variables
double point_multiplier;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   // Adjust for 4 or 5 digit brokers
   if(Digits == 3 || Digits == 5) point_multiplier = 10.0;
   else point_multiplier = 1.0;
   
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   // Only execute on new bar to prevent M1 tick-level whipsaws
   static datetime last_time = 0;
   datetime current_time = iTime(_Symbol, PERIOD_M1, 0);
   if(current_time == last_time) return;
   
   // We only trade if there are no open positions for this EA
   if(CountOpenPositions() > 0) return;

   //--- 1. Calculate Indicators ---
   // Using Shift 1 (last closed bar) and Shift 2 (previous closed bar)
   
   // EMA Filter
   double ema1 = iMA(_Symbol, PERIOD_M1, InpEMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
   
   // Stochastic Current (Shift 1)
   double stoch_K1 = iStochastic(_Symbol, PERIOD_M1, InpKPeriod, InpDPeriod, InpSlowing, MODE_SMA, 0, MODE_MAIN, 1);
   double stoch_D1 = iStochastic(_Symbol, PERIOD_M1, InpKPeriod, InpDPeriod, InpSlowing, MODE_SMA, 0, MODE_SIGNAL, 1);
   
   // Stochastic Previous (Shift 2)
   double stoch_K2 = iStochastic(_Symbol, PERIOD_M1, InpKPeriod, InpDPeriod, InpSlowing, MODE_SMA, 0, MODE_MAIN, 2);
   double stoch_D2 = iStochastic(_Symbol, PERIOD_M1, InpKPeriod, InpDPeriod, InpSlowing, MODE_SMA, 0, MODE_SIGNAL, 2);

   // Current Price (Last closed bar close)
   double close1 = iClose(_Symbol, PERIOD_M1, 1);

   //--- 2. Logic Evaluation ---
   
   bool isUptrend   = close1 > ema1;
   bool isDowntrend = close1 < ema1;
   
   // BUY LOGIC: Price > EMA AND %K crosses above %D from BELOW the Oversold Level
   bool buyCondition = isUptrend && 
                       (stoch_K2 < InpOSLevel && stoch_D2 < InpOSLevel) && // Was in Oversold zone
                       (stoch_K2 <= stoch_D2) &&                           // K was below or equal to D
                       (stoch_K1 > stoch_D1);                              // K crossed above D

   // SELL LOGIC: Price < EMA AND %K crosses below %D from ABOVE the Overbought Level
   bool sellCondition = isDowntrend && 
                        (stoch_K2 > InpOBLevel && stoch_D2 > InpOBLevel) && // Was in Overbought zone
                        (stoch_K2 >= stoch_D2) &&                           // K was above or equal to D
                        (stoch_K1 < stoch_D1);                              // K crossed below D

   //--- 3. Trade Execution ---
   
   double sl, tp;
   
   if(buyCondition)
     {
      sl = Ask - (InpStopLossPips * point_multiplier * Point);
      tp = Ask + (InpTakeProfitPips * point_multiplier * Point);
      
      int ticket = OrderSend(_Symbol, OP_BUY, InpLotSize, Ask, InpSlippage, sl, tp, "M1 Stoch Scalp Buy", InpMagicNumber, 0, clrBlue);
      if(ticket > 0) last_time = current_time; // Mark bar as traded
     }
     
   else if(sellCondition)
     {
      sl = Bid + (InpStopLossPips * point_multiplier * Point);
      tp = Bid - (InpTakeProfitPips * point_multiplier * Point);
      
      int ticket = OrderSend(_Symbol, OP_SELL, InpLotSize, Bid, InpSlippage, sl, tp, "M1 Stoch Scalp Sell", InpMagicNumber, 0, clrRed);
      if(ticket > 0) last_time = current_time; // Mark bar as traded
     }
  }

//+------------------------------------------------------------------+
//| Helper: Count open positions for this EA                         |
//+------------------------------------------------------------------+
int CountOpenPositions()
  {
   int count = 0;
   for(int i = 0; i < OrdersTotal(); i++)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderSymbol() == _Symbol && OrderMagicNumber() == InpMagicNumber)
           {
            count++;
           }
        }
     }
   return count;
  }
//+------------------------------------------------------------------+
FTtrader
Posts: 316
Joined: Mon Aug 03, 2026 2:43 pm

Re: Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision

Post by FTtrader »

Strategy Configuration Guide (How to set your inputs):

When you attach this EA to your M1 chart, you will get an input window where you can plug in the specific regimes you mentioned:

Balanced / Default M1

InpKPeriod: 5, InpDPeriod: 3, InpSlowing: 3

InpOBLevel: 80, InpOSLevel: 20

Strong Intraday Trends (London/NY)

InpKPeriod: 9, InpDPeriod: 3, InpSlowing: 1

InpOBLevel: 85, InpOSLevel: 15 (Widened to prevent premature shakeouts)

High Volatility (GBP/JPY, XAU/USD)

InpKPeriod: 5, InpDPeriod: 2, InpSlowing: 2

InpOBLevel: 85, InpOSLevel: 15

Ranging / Asian Session

InpKPeriod: 5, InpDPeriod: 3, InpSlowing: 3

InpOBLevel: 70, InpOSLevel: 30 (Tightened for higher frequency mean-reversion)
FTtrader
Posts: 316
Joined: Mon Aug 03, 2026 2:43 pm

Re: Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision

Post by FTtrader »

Important M1 Scalping Notes for this Code:

Execution on Bar Close: To prevent "random market microstructure noise" and tick-level whipsaws, the code evaluates signals specifically when the 1-minute candle closes. Trading mid-candle on M1 often results in fake crossovers that disappear before the bar closes.

Risk Variables: The EA defaults to 3 pips SL and 5 pips TP (as requested). Make sure your broker has tight spreads. If your spread on an M1 pair is 1.5 pips, half your profit potential is instantly eaten by the broker. For an automated 3-to-5 pip scalper, consider using a zero-spread/raw ECN account with commission pricing.
FTtrader
Posts: 316
Joined: Mon Aug 03, 2026 2:43 pm

Re: Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision

Post by FTtrader »

n MQL5, indicator values are handled via indicator handles and dynamic data buffers, and order execution is streamlined using the standard CTrade class.

How to Install and Run in MT5:

1.) Open your MT5 terminal.

2.) Press F4 to launch the MetaEditor 5.

3.) In the top-left Navigator, right-click the Experts folder and select New File (or press Ctrl + N), choose Expert Advisor (template), and name it M1_Stoch_Scalper_MT5.

4.) Delete all auto-generated template code and paste the code below.

5.) Click Compile (F7) and verify there are 0 errors, 0 warnings.

6.) Drag the EA from MT5 Navigator onto your M1 chart and ensure Algo Trading is enabled in the top toolbar.

Code: Select all

//+------------------------------------------------------------------+
//|                                        M1_Stoch_Scalper_MT5.mq5  |
//|                                     Institutional Scalping Logic |
//+------------------------------------------------------------------+
#property copyright "Institutional Scalper"
#property link      ""
#property version   "1.00"

// Standard MQL5 Trade Library
#include <Trade\Trade.mqh>
CTrade trade;

//+------------------------------------------------------------------+
//| Input Parameters                                                 |
//+------------------------------------------------------------------+
input group "--- Stochastic Settings ---"
input int      InpKPeriod        = 5;      // %K Period (5, 9, or 5)
input int      InpDPeriod        = 3;      // %D Period (3, 3, or 2)
input int      InpSlowing        = 3;      // Slowing (3, 1, or 2)
input int      InpOBLevel        = 80;     // Overbought (85: Volatile, 70: Range)
input int      InpOSLevel        = 20;     // Oversold (15: Volatile, 30: Range)

input group "--- Trend Filter ---"
input int      InpEMAPeriod      = 50;     // EMA Period (50 or 200)

input group "--- Execution & Risk ---"
input double   InpLotSize        = 0.1;    // Fixed Lot Size
input int      InpTakeProfitPips = 5;      // Take Profit (Pips)
input int      InpStopLossPips   = 3;      // Stop Loss (Pips)
input ulong    InpSlippage       = 10;     // Max Slippage / Deviation (Points)
input ulong    InpMagicNumber    = 98765;  // Magic Number

// Global Variables
int    handle_ema   = INVALID_HANDLE;
int    handle_stoch = INVALID_HANDLE;
double pip_multiplier;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   // Configure Pip Size for 3/5 digit broker pricing
   if(_Digits == 3 || _Digits == 5) 
      pip_multiplier = 10.0 * _Point;
   else 
      pip_multiplier = _Point;

   // Setup CTrade execution helper
   trade.SetExpertMagicNumber(InpMagicNumber);
   trade.SetDeviationInPoints(InpSlippage);
   trade.SetTypeFillingBySymbol(_Symbol);

   // Initialize Indicator Handles on M1 timeframe
   handle_ema = iMA(_Symbol, PERIOD_M1, InpEMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   if(handle_ema == INVALID_HANDLE)
     {
      Print("Error creating EMA handle: ", GetLastError());
      return(INIT_FAILED);
     }

   handle_stoch = iStochastic(_Symbol, PERIOD_M1, InpKPeriod, InpDPeriod, InpSlowing, MODE_SMA, STO_LOWHIGH);
   if(handle_stoch == INVALID_HANDLE)
     {
      Print("Error creating Stochastic handle: ", GetLastError());
      return(INIT_FAILED);
     }

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   // Release indicator handles from memory
   if(handle_ema != INVALID_HANDLE)   IndicatorRelease(handle_ema);
   if(handle_stoch != INVALID_HANDLE) IndicatorRelease(handle_stoch);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   // 1. New Bar Execution Check (Prevents tick whipsaws on M1)
   static datetime last_bar_time = 0;
   datetime current_bar_time = iTime(_Symbol, PERIOD_M1, 0);
   if(current_bar_time == 0 || current_bar_time == last_bar_time) 
      return;

   // 2. Position Check (Scalp 1 active trade at a time)
   if(CountOpenPositions() > 0) 
      return;

   // 3. Populate Indicator Buffers (Shift 1 = index 0, Shift 2 = index 1)
   double ema[];
   double stoch_k[];
   double stoch_d[];
   double close[];

   ArraySetAsSeries(ema, true);
   ArraySetAsSeries(stoch_k, true);
   ArraySetAsSeries(stoch_d, true);
   ArraySetAsSeries(close, true);

   // Copy 2 closed bars (starting at shift 1)
   if(CopyBuffer(handle_ema, 0, 1, 2, ema) < 2) return;
   if(CopyBuffer(handle_stoch, 0, 1, 2, stoch_k) < 2) return; // %K Line (Main)
   if(CopyBuffer(handle_stoch, 1, 1, 2, stoch_d) < 2) return; // %D Line (Signal)
   if(CopyClose(_Symbol, PERIOD_M1, 1, 2, close) < 2) return;

   // Index 0 = Shift 1 (last closed candle)
   // Index 1 = Shift 2 (previous closed candle)
   double close1   = close[0];
   double ema1     = ema[0];
   double stoch_K1 = stoch_k[0];
   double stoch_D1 = stoch_d[0];
   double stoch_K2 = stoch_k[1];
   double stoch_D2 = stoch_d[1];

   // 4. Trend Evaluation
   bool isUptrend   = (close1 > ema1);
   bool isDowntrend = (close1 < ema1);

   // 5. Signal Evaluation
   // BUY: Price > EMA AND %K crossed above %D inside Oversold zone
   bool buyCondition = isUptrend && 
                       (stoch_K2 < InpOSLevel && stoch_D2 < InpOSLevel) &&
                       (stoch_K2 <= stoch_D2) &&
                       (stoch_K1 > stoch_D1);

   // SELL: Price < EMA AND %K crossed below %D inside Overbought zone
   bool sellCondition = isDowntrend && 
                        (stoch_K2 > InpOBLevel && stoch_D2 > InpOBLevel) &&
                        (stoch_K2 >= stoch_D2) &&
                        (stoch_K1 < stoch_D1);

   // 6. Trade Execution
   MqlTick tick;
   if(!SymbolInfoTick(_Symbol, tick)) return;

   if(buyCondition)
     {
      double sl = NormalizeDouble(tick.ask - (InpStopLossPips * pip_multiplier), _Digits);
      double tp = NormalizeDouble(tick.ask + (InpTakeProfitPips * pip_multiplier), _Digits);

      if(trade.Buy(InpLotSize, _Symbol, tick.ask, sl, tp, "M1 Stoch Scalp Buy"))
        {
         last_bar_time = current_bar_time; // Mark candle as traded
        }
     }
   else if(sellCondition)
     {
      double sl = NormalizeDouble(tick.bid + (InpStopLossPips * pip_multiplier), _Digits);
      double tp = NormalizeDouble(tick.bid - (InpTakeProfitPips * pip_multiplier), _Digits);

      if(trade.Sell(InpLotSize, _Symbol, tick.bid, sl, tp, "M1 Stoch Scalp Sell"))
        {
         last_bar_time = current_bar_time; // Mark candle as traded
        }
     }
  }

//+------------------------------------------------------------------+
//| Count Open Positions matching Symbol and Magic Number            |
//+------------------------------------------------------------------+
int CountOpenPositions()
  {
   int count = 0;
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      if(ticket > 0)
        {
         if(PositionGetString(POSITION_SYMBOL) == _Symbol && 
            PositionGetInteger(POSITION_MAGIC) == InpMagicNumber)
           {
            count++;
           }
        }
     }
   return count;
  }
//+------------------------------------------------------------------+
FTtrader
Posts: 316
Joined: Mon Aug 03, 2026 2:43 pm

Re: Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision

Post by FTtrader »

Key MT5 Improvements in this Version:

trade.SetTypeFillingBySymbol(_Symbol): MT5 brokers use different execution fill policies (ORDER_FILLING_IOC, ORDER_FILLING_FOK, or ORDER_FILLING_RETURN). The script sets execution compatibility automatically to eliminate "Unsupported filling mode" errors.

Handle-Based Indicators: In MT5, indicators are calculated in the background by the terminal core via handle_ema and handle_stoch. CopyBuffer only reads the two bars required, keeping CPU footprint minimal during M1 backtesting.

Tick-level Array Precision: The arrays are set as series (ArraySetAsSeries(..., true)), maintaining the familiar indexing model where index 0 is the most recently closed candle (Shift 1) and index 1 is the candle before it (Shift 2).
FTtrader
Posts: 316
Joined: Mon Aug 03, 2026 2:43 pm

Re: Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision

Post by FTtrader »

cTrader uses a very clean event-driven architecture via the cAlgo.API. Unlike MetaTrader, where we have to manually check timestamps inside the OnTick function to find the close of a bar, cTrader gives us a native OnBarClosed() event. This makes the institutional scalping logic much faster and cleaner to process.

How to Install and Run in cTrader:

1.) Open your cTrader platform and click on the Automate tab on the left menu.

2.) Click the New cBot button (usually a + sign) at the top of the cBots list. Name it M1_Stoch_Scalper.

3.) Erase all the default code in the built-in code editor and paste the C# code below.

4.) Click the Build button (hammer icon) at the top of the editor.

5.) Once compiled successfully, click Add Instance, attach it to a 1-Minute (m1) chart, configure your parameters, and press Play to start trading.

Code: Select all

using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class M1StochScalper : Robot
    {
        // --- Stochastic Settings ---
        [Parameter("Stoch %K Period", Group = "Stochastic Settings", DefaultValue = 5)]
        public int KPeriod { get; set; }

        [Parameter("Stoch %D Period", Group = "Stochastic Settings", DefaultValue = 3)]
        public int DPeriod { get; set; }

        [Parameter("Stoch Slowing", Group = "Stochastic Settings", DefaultValue = 3)]
        public int Slowing { get; set; }

        [Parameter("Overbought Level", Group = "Stochastic Settings", DefaultValue = 80)]
        public int OverboughtLevel { get; set; }

        [Parameter("Oversold Level", Group = "Stochastic Settings", DefaultValue = 20)]
        public int OversoldLevel { get; set; }

        // --- Trend Filter ---
        [Parameter("EMA Period", Group = "Trend Filter", DefaultValue = 50)]
        public int EmaPeriod { get; set; }

        // --- Execution & Risk ---
        [Parameter("Lot Size", Group = "Execution & Risk", DefaultValue = 0.1)]
        public double LotSize { get; set; }

        [Parameter("Take Profit (Pips)", Group = "Execution & Risk", DefaultValue = 5)]
        public double TakeProfitPips { get; set; }

        [Parameter("Stop Loss (Pips)", Group = "Execution & Risk", DefaultValue = 3)]
        public double StopLossPips { get; set; }

        // Internal Variables
        private StochasticOscillator _stochastic;
        private ExponentialMovingAverage _ema;
        private const string InstanceLabel = "M1StochScalper";

        protected override void OnStart()
        {
            // Initialize Indicators
            // Note: cTrader parameter order is KPeriods, KSlowing, DPeriods, MAType
            _stochastic = Indicators.StochasticOscillator(KPeriod, Slowing, DPeriod, MovingAverageType.Simple);
            _ema = Indicators.ExponentialMovingAverage(Bars.ClosePrices, EmaPeriod);
        }

        // cTrader natively handles "Bar Close" execution without needing timestamp hacks
        protected override void OnBarClosed()
        {
            // 1. Position Check (Scalp 1 active trade at a time for this specific bot)
            var activePositions = Positions.FindAll(InstanceLabel, SymbolName);
            if (activePositions.Length > 0)
                return;

            // 2. Extract Indicator Values
            // .Last(1) gets the value of the candle that JUST closed.
            // .Last(2) gets the value of the candle before the one that just closed.
            double ema1 = _ema.Result.Last(1);
            double close1 = Bars.ClosePrices.Last(1);

            double stochK1 = _stochastic.PercentK.Last(1);
            double stochD1 = _stochastic.PercentD.Last(1);
            
            double stochK2 = _stochastic.PercentK.Last(2);
            double stochD2 = _stochastic.PercentD.Last(2);

            // 3. Trend Evaluation
            bool isUptrend = close1 > ema1;
            bool isDowntrend = close1 < ema1;

            // 4. Signal Evaluation
            // BUY: Price > EMA AND %K crossed above %D inside Oversold zone
            bool buyCondition = isUptrend &&
                                (stochK2 < OversoldLevel && stochD2 < OversoldLevel) &&
                                (stochK2 <= stochD2) &&
                                (stochK1 > stochD1);

            // SELL: Price < EMA AND %K crossed below %D inside Overbought zone
            bool sellCondition = isDowntrend &&
                                 (stochK2 > OverboughtLevel && stochD2 > OverboughtLevel) &&
                                 (stochK2 >= stochD2) &&
                                 (stochK1 < stochD1);

            // 5. Trade Execution
            if (buyCondition)
            {
                ExecuteOrder(TradeType.Buy);
            }
            else if (sellCondition)
            {
                ExecuteOrder(TradeType.Sell);
            }
        }

        private void ExecuteOrder(TradeType tradeType)
        {
            // cTrader requires volume in Units rather than Lots (e.g., 0.1 Lots = 10,000 Units)
            // This natively converts your Lot Size input into the broker's correct unit format
            double volumeInUnits = Symbol.QuantityToVolumeInUnits(LotSize);
            
            // Execute the market order
            ExecuteMarketOrder(tradeType, SymbolName, volumeInUnits, InstanceLabel, StopLossPips, TakeProfitPips);
        }
    }
}
FTtrader
Posts: 316
Joined: Mon Aug 03, 2026 2:43 pm

Re: Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision

Post by FTtrader »

Key cTrader (C#) Advantages in this Code:

OnBarClosed() Event: We completely removed the OnTick() method and its clunky timestamp trackers. Using OnBarClosed() guarantees that fake tick-level whipsaws inside the minute will never trigger your execution logic.

Simplified Indexing (.Last(x)): Instead of MetaTrader's reverse-array shifting, cTrader reads left-to-right. Using .Last(1) always returns the exact state of the candle that just finished closing, and .Last(2) is the candle right before it.

Native Lot Conversion: The function Symbol.QuantityToVolumeInUnits(LotSize) prevents execution errors by automatically normalizing standard FX lots (like 0.1) into the raw unit sizes (like 10,000) that the FIX API routing actually requires.
FTtrader
Posts: 316
Joined: Mon Aug 03, 2026 2:43 pm

Re: Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision

Post by FTtrader »

And here is the complete, natively optimized Pine Script (v5) Strategy for TradingView.

Because TradingView scripts run sequentially from left to right and calculate on bar closes by default, Pine Script natively handles the M1 tick-filtering without needing the manual array shifts required in MT4/5.

How to Install and Run in TradingView:

1.) Open your TradingView chart and set the timeframe to 1 minute (1m).

2.) At the bottom of the screen, click the Pine Editor tab.

3.) Delete any default code in the editor, and paste the code below.

4.) Click Save (name it "M1 Stoch Scalper") and then click Add to Chart.

5.) You can click the Gear Icon (Settings) on the script in your chart to adjust the Stochastic regimes and Risk variables.

Code: Select all

//@version=5
strategy("M1 Institutional Stoch Scalper", shorttitle="M1 Stoch Scalp", overlay=true, calc_on_every_tick=false, margin_long=100, margin_short=100)

// =========================================================================
// 1. INPUT PARAMETERS
// =========================================================================
grp_stoch = "--- Stochastic Settings ---"
k_len   = input.int(5, title="%K Period", group=grp_stoch, tooltip="5 for standard, 9 for trend, 5 for volatile")
d_len   = input.int(3, title="%D Period", group=grp_stoch, tooltip="3 for standard, 3 for trend, 2 for volatile")
smooth  = input.int(3, title="Slowing", group=grp_stoch, tooltip="3 for standard, 1 for trend, 2 for volatile")
ob      = input.float(80, title="Overbought Level", group=grp_stoch)
os      = input.float(20, title="Oversold Level", group=grp_stoch)

grp_trend = "--- Trend Filter ---"
ema_len = input.int(50, title="EMA Period", group=grp_trend, tooltip="Filter trades against the 50 or 200 EMA")

grp_risk = "--- Execution & Risk ---"
lot_size = input.float(0.1, title="Lot Size", group=grp_risk)
tp_pips  = input.float(5.0, title="Take Profit (Pips)", group=grp_risk)
sl_pips  = input.float(3.0, title="Stop Loss (Pips)", group=grp_risk)

// Configure pip multiplier (Standard Forex: 1 pip = 10 ticks)
// If trading non-forex pairs (like Crypto), you may need to adjust this logic.
pip_mult = syminfo.mintick * 10

// =========================================================================
// 2. INDICATOR CALCULATIONS
// =========================================================================
// Trend Filter (EMA)
ema_val = ta.ema(close, ema_len)
plot(ema_val, color=color.new(color.blue, 0), title="Trend EMA", linewidth=2)

// Stochastic Oscillator (MT4 Mode SMA formula)
raw_k = ta.stoch(close, high, low, k_len)
k_line = ta.sma(raw_k, smooth)
d_line = ta.sma(k_line, d_len)

// =========================================================================
// 3. LOGIC EVALUATION
// =========================================================================
// Check trend bias
is_uptrend   = close > ema_val
is_downtrend = close < ema_val

// Track zone status on the previous closed bar
was_os = k_line[1] < os and d_line[1] < os
was_ob = k_line[1] > ob and d_line[1] > ob

// Identify crossovers exactly as they close
bull_cross = ta.crossover(k_line, d_line)
bear_cross = ta.crossunder(k_line, d_line)

// Final Execution Triggers
buy_cond  = is_uptrend and was_os and bull_cross
sell_cond = is_downtrend and was_ob and bear_cross

// =========================================================================
// 4. TRADE EXECUTION
// =========================================================================
// TradingView quantities are in units. 1 Standard Forex Lot = 100,000 units.
trade_qty = lot_size * 100000

if buy_cond and strategy.position_size == 0
    strategy.entry("Long", strategy.long, qty=trade_qty)
    
    // Calculate static SL and TP price levels from entry
    sl_price = close - (sl_pips * pip_mult)
    tp_price = close + (tp_pips * pip_mult)
    
    strategy.exit("Exit Long", "Long", stop=sl_price, limit=tp_price)

if sell_cond and strategy.position_size == 0
    strategy.entry("Short", strategy.short, qty=trade_qty)
    
    // Calculate static SL and TP price levels from entry
    sl_price = close + (sl_pips * pip_mult)
    tp_price = close - (tp_pips * pip_mult)
    
    strategy.exit("Exit Short", "Short", stop=sl_price, limit=tp_price)
Post Reply