Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision
Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision
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.
Re: Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision
// 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];
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.
Re: Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision
Hi PTscalpers,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];
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;
}
//+------------------------------------------------------------------+Re: Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision
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)
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)
Re: Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision
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.
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.
Re: Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision
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.
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;
}
//+------------------------------------------------------------------+Re: Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision
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).
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).
Re: Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision
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.
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);
}
}
}Re: Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision
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.
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.
Re: Optimal 1-Minute Stochastic Settings: Ditching 14,3,3 for High-Frequency Precision
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.
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)