Page 2 of 3
Re: The Market Doesn’t Care About Your Feelings
Posted: Sat Sep 26, 2026 5:42 pm
by PTScalper
How to use this for execution discipline:
No Guessing the Stop: The moment a sweep occurs, the orange crosses plot exactly at the high/low of that wick. That is your non-negotiable exit.
The Time-in-Trade Check: If you enter after the sweep and the market just consolidates at your entry, the bars will eventually paint gray (after 5 candles by default). This physically reminds you that the momentum you were betting on did not arrive, prompting a scratch before it turns into a drawn-out loss.
Re: The Market Doesn’t Care About Your Feelings
Posted: Sat Sep 26, 2026 5:42 pm
by PTScalper
Here is a complete Pine Script strategy built purely around raw price action, avoiding lagging indicators entirely. It focuses on the interaction between Daily structure and 15-minute execution, specifically hunting for liquidity sweeps of the Previous Day's High (PDH) or Low (PDL).
This script is designed for the M15 chart. It automatically pulls the D1 levels, highlights them, and issues trade entries with strictly defined invalidation wicks.
Code: Select all
//@version=5
strategy("D1/M15 Pure Price Action Sweep", overlay=true, initial_capital=10000, default_qty_type=strategy.percent_of_equity, default_qty_value=1)
// =========================================================================
// 1. Fetching Higher Timeframe Structure (Daily)
// =========================================================================
// Using lookahead_on with high[1] / low[1] safely fetches yesterday's levels without repainting today.
pdh = request.security(syminfo.tickerid, "D", high[1], lookahead=barmerge.lookahead_on)
pdl = request.security(syminfo.tickerid, "D", low[1], lookahead=barmerge.lookahead_on)
// Plot the Daily Liquidity Pools on the M15 chart
plot(pdh, color=color.new(color.red, 50), style=plot.style_linebr, linewidth=2, title="Previous Day High (BSL)")
plot(pdl, color=color.new(color.green, 50), style=plot.style_linebr, linewidth=2, title="Previous Day Low (SSL)")
// =========================================================================
// 2. M15 Execution Trigger: The Liquidity Sweep
// =========================================================================
// Bearish setup: M15 wick pierces PDH, but closes back inside (below) the level.
bearishSweep = (high > pdh) and (close < pdh) and (open < pdh)
// Bullish setup: M15 wick pierces PDL, but closes back inside (above) the level.
bullishSweep = (low < pdl) and (close > pdl) and (open > pdl)
// =========================================================================
// 3. Trade Execution & Strict Invalidation
// =========================================================================
var float hardStop = na
var float entryPrice = na
// Fixed R:R target (e.g., 2R)
rr_ratio = input.float(2.0, title="Risk/Reward Ratio", step=0.1)
if bearishSweep and strategy.position_size == 0
// Stop is exactly at the high of the sweeping wick
hardStop := high
entryPrice := close
risk = hardStop - entryPrice
target = entryPrice - (risk * rr_ratio)
strategy.entry("Short Sweep", strategy.short)
strategy.exit("Exit Short", "Short Sweep", stop=hardStop, limit=target)
if bullishSweep and strategy.position_size == 0
// Stop is exactly at the low of the sweeping wick
hardStop := low
entryPrice := close
risk = entryPrice - hardStop
target = entryPrice + (risk * rr_ratio)
strategy.entry("Long Sweep", strategy.long)
strategy.exit("Exit Long", "Long Sweep", stop=hardStop, limit=target)
// =========================================================================
// 4. Visualizing the Process
// =========================================================================
// Plot a small dot at the exact invalidation level while in a trade
plot(strategy.position_size != 0 ? hardStop : na, color=color.orange, style=plot.style_circles, linewidth=2, title="Active Stop Loss")
// Mark the trigger candles
plotshape(bearishSweep, style=shape.triangledown, location=location.abovebar, color=color.red, size=size.small, title="Bearish Trigger")
plotshape(bullishSweep, style=shape.triangleup, location=location.belowbar, color=color.green, size=size.small, title="Bullish Trigger")
Re: The Market Doesn’t Care About Your Feelings
Posted: Sat Sep 26, 2026 5:42 pm
by PTScalper
How this enforces the process:
The Framework: The strategy anchors itself to daily price action. Instead of trading arbitrary noise in the middle of a range, it only wakes up when major Daily liquidity is tested.
The Trigger: It forces patience. The condition close < pdh requires the M15 candle to actually close to confirm the sweep, preventing you from getting chopped up trying to short a full-bodied breakout.
The Invalidation: The strategy.exit function instantly maps the hard stop to the absolute extreme of the sweeping wick. It completely removes the temptation to manually negotiate the stop level.
Re: The Market Doesn’t Care About Your Feelings
Posted: Sat Sep 26, 2026 5:43 pm
by PTScalper
To risk exactly 1% of your account equity per trade, you have to disconnect the position size from the asset's price and tie it entirely to the distance of your stop loss.
If your stop is 5 pips away, you need a larger lot size. If the stop is 15 pips away, the lot size must dynamically shrink so the total monetary risk remains exactly 1%.
Here is the modified script. The core change uses the formula:
Risk Amount = Account Equity * 1%
Position Size = Risk Amount / (Stop Distance * Point Value)
Re: The Market Doesn’t Care About Your Feelings
Posted: Sat Sep 26, 2026 5:43 pm
by PTScalper
Pine script ver. 2.00
Code: Select all
//@version=5
strategy("D1/M15 Sweep - 1% Fixed Risk", overlay=true, initial_capital=10000)
// =========================================================================
// 1. Risk Management Inputs
// =========================================================================
riskPercent = input.float(1.0, title="Risk Per Trade (%)", step=0.1)
rr_ratio = input.float(2.0, title="Risk/Reward Ratio", step=0.1)
// =========================================================================
// 2. Fetching Higher Timeframe Structure (Daily)
// =========================================================================
pdh = request.security(syminfo.tickerid, "D", high[1], lookahead=barmerge.lookahead_on)
pdl = request.security(syminfo.tickerid, "D", low[1], lookahead=barmerge.lookahead_on)
plot(pdh, color=color.new(color.red, 50), style=plot.style_linebr, linewidth=2, title="PDH")
plot(pdl, color=color.new(color.green, 50), style=plot.style_linebr, linewidth=2, title="PDL")
// =========================================================================
// 3. M15 Execution Trigger: The Liquidity Sweep
// =========================================================================
bearishSweep = (high > pdh) and (close < pdh) and (open < pdh)
bullishSweep = (low < pdl) and (close > pdl) and (open > pdl)
// =========================================================================
// 4. Trade Execution & Dynamic Sizing
// =========================================================================
var float hardStop = na
var float entryPrice = na
if bearishSweep and strategy.position_size == 0
hardStop := high
entryPrice := close
// Calculate exact risk per trade based on current equity
riskAmount = strategy.equity * (riskPercent / 100)
stopDistance = hardStop - entryPrice
// syminfo.pointvalue ensures this works across Forex, Gold, and Equities
posSize = riskAmount / (stopDistance * syminfo.pointvalue)
targetPrice = entryPrice - (stopDistance * rr_ratio)
strategy.entry("Short Sweep", strategy.short, qty=posSize)
strategy.exit("Exit Short", "Short Sweep", stop=hardStop, limit=targetPrice)
if bullishSweep and strategy.position_size == 0
hardStop := low
entryPrice := close
riskAmount = strategy.equity * (riskPercent / 100)
stopDistance = entryPrice - hardStop
posSize = riskAmount / (stopDistance * syminfo.pointvalue)
targetPrice = entryPrice + (stopDistance * rr_ratio)
strategy.entry("Long Sweep", strategy.long, qty=posSize)
strategy.exit("Exit Long", "Long Sweep", stop=hardStop, limit=targetPrice)
// =========================================================================
// 5. Visualizing the Process
// =========================================================================
plot(strategy.position_size != 0 ? hardStop : na, color=color.orange, style=plot.style_circles, linewidth=2, title="Active Stop Loss")
plotshape(bearishSweep, style=shape.triangledown, location=location.abovebar, color=color.red, size=size.small)
plotshape(bullishSweep, style=shape.triangleup, location=location.belowbar, color=color.green, size=size.small)
Re: The Market Doesn’t Care About Your Feelings
Posted: Sat Sep 26, 2026 5:43 pm
by PTScalper
Why syminfo.pointvalue is Critical
If you apply this to EUR/USD, the stop distance might be 0.00050 (5 pips). If you apply it to an equity, the stop distance might be 1.50 ($1.50). Multiplying the raw stop distance by syminfo.pointvalue normalizes the math across different asset classes, ensuring the 1% risk rule calculates the correct number of lots or shares regardless of what chart you load the script onto.
Re: The Market Doesn’t Care About Your Feelings
Posted: Sat Sep 26, 2026 5:44 pm
by PTScalper
Here is the direct C# cAlgo translation of the strategy. Since cTrader’s API handles multi-timeframe data and order sizing a bit differently than Pine Script, this cBot uses MarketData.GetBars(TimeFrame.Daily) to fetch the true Previous Day High/Low and implements precise volume normalization based on pip value.
Code: Select all
using System;
using cAlgo.API;
using cAlgo.API.Internals;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class D1M15SweepBot : Robot
{
[Parameter("Risk Per Trade (%)", DefaultValue = 1.0, MinValue = 0.1, Step = 0.1)]
public double RiskPercent { get; set; }
[Parameter("Risk/Reward Ratio", DefaultValue = 2.0, MinValue = 0.5, Step = 0.1)]
public double RiskRewardRatio { get; set; }
private Bars _dailyBars;
protected override void OnStart()
{
// Fetch the Daily timeframe data to anchor the liquidity levels
_dailyBars = MarketData.GetBars(TimeFrame.Daily);
}
protected override void OnBar()
{
// Prevent pyramiding: only one active sweep trade at a time
if (Positions.Count(p => p.SymbolName == SymbolName && p.Label == "Sweep") > 0)
return;
// Evaluate price action on the most recently closed M15 bar
int m15Index = Bars.Count - 2;
var closedBar = Bars[m15Index];
// Align the M15 bar's date with the Daily timeframe to find yesterday's exact bar
int dailyIndex = _dailyBars.OpenTimes.GetIndexByTime(closedBar.OpenTime.Date);
if (dailyIndex <= 0) return;
var yesterdayDaily = _dailyBars[dailyIndex - 1];
double pdh = yesterdayDaily.High;
double pdl = yesterdayDaily.Low;
// Bearish Setup: Wick pierces PDH, but closes below
bool bearishSweep = closedBar.High > pdh && closedBar.Close < pdh && closedBar.Open < pdh;
// Bullish Setup: Wick pierces PDL, but closes above
bool bullishSweep = closedBar.Low < pdl && closedBar.Close > pdl && closedBar.Open > pdl;
if (bearishSweep)
{
ExecuteSweepTrade(TradeType.Sell, closedBar.High, closedBar.Close);
}
else if (bullishSweep)
{
ExecuteSweepTrade(TradeType.Buy, closedBar.Low, closedBar.Close);
}
}
private void ExecuteSweepTrade(TradeType tradeType, double hardStopPrice, double entryPrice)
{
// Calculate absolute monetary risk based on current equity
double riskAmount = Account.Equity * (RiskPercent / 100);
// Convert stop distance into exact pips for cTrader execution
double stopLossPips = Math.Abs(entryPrice - hardStopPrice) / Symbol.PipSize;
if (stopLossPips <= 0) return; // Guard against divide-by-zero on zero-pip wicks
double takeProfitPips = stopLossPips * RiskRewardRatio;
// cTrader volume calculation: Normalize for exact lot step sizes across Forex/Metals
double rawVolume = riskAmount / (stopLossPips * Symbol.PipValue);
double normalizedVolume = Symbol.NormalizeVolumeInUnits(rawVolume, RoundingMode.Down);
// Safety check: Prevent broker rejection if calculated risk yields a micro-lot below minimum limits
if (normalizedVolume < Symbol.VolumeInUnitsMin)
{
Print("Calculated volume is below broker minimum. Trade aborted to protect risk integrity.");
return;
}
ExecuteMarketOrder(tradeType, SymbolName, normalizedVolume, "Sweep", stopLossPips, takeProfitPips);
}
}
}
Re: The Market Doesn’t Care About Your Feelings
Posted: Sat Sep 26, 2026 5:44 pm
by PTScalper
Key structural translations for cTrader:
Timeframe Independence: _dailyBars.OpenTimes.GetIndexByTime maps the closed M15 candle's timestamp exactly to the daily data series. This is much safer than simply grabbing Bars.Last(1) on a daily chart, as it avoids misalignment caused by weekend gaps, server timezone shifts, or backtesting anomalies.
Asset-Agnostic Sizing: The formula riskAmount / (stopLossPips * Symbol.PipValue) leverages cTrader's native pip value calculator. This guarantees the 1% risk math remains perfectly accurate whether the cBot is attached to EUR/USD, XAU/USD, or an equity index.
Volume Normalization: Broker APIs reject raw double values for volume (e.g., trying to buy 1,234.567 units). Symbol.NormalizeVolumeInUnits safely rounds the calculated risk volume down to the nearest acceptable step size (like 1,000 units for a micro-lot) so execution never fails at the server level.
Re: The Market Doesn’t Care About Your Feelings
Posted: Sat Sep 26, 2026 5:46 pm
by PTScalper
Here are the complete Expert Advisors (EAs) for both MetaTrader 5 and MetaTrader 4.
MetaTrader handles position sizing completely differently than Pine Script or cTrader. Instead of abstract "points," it uses TICK_VALUE and TICK_SIZE. The scripts below calculate the exact monetary value of a single tick movement for your specific asset, divide your 1% account risk by that value, and securely floor the lot size to your broker's allowed volume steps so trade execution never fails.
Re: The Market Doesn’t Care About Your Feelings
Posted: Sat Sep 26, 2026 5:46 pm
by PTScalper
1. MetaTrader 5 (MQL5) Expert Advisor
MQL5 relies on the standard CTrade library to manage order execution cleanly. Save this as a .mq5 file.
Code: Select all
//+------------------------------------------------------------------+
//| D1M15_Sweep_MT5.mq5 |
//+------------------------------------------------------------------+
#property strict
#include <Trade\Trade.mqh>
input double RiskPercent = 1.0; // Risk Per Trade (%)
input double RiskRewardRatio = 2.0; // Risk/Reward Ratio
input ulong MagicNumber = 123456; // EA Magic Number
CTrade trade;
int OnInit()
{
trade.SetExpertMagicNumber(MagicNumber);
return(INIT_SUCCEEDED);
}
void OnTick()
{
// 1. Execute only on the open of a new M15 bar
static datetime lastTime = 0;
datetime currentTime = iTime(_Symbol, PERIOD_M15, 0);
if(currentTime == lastTime || currentTime == 0) return;
// 2. Prevent pyramiding: Check if a trade is already active
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong posTicket = PositionGetTicket(i); // Automatically selects the position
if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == MagicNumber)
return;
}
lastTime = currentTime;
// 3. Fetch Daily Liquidity Pools (Yesterday's High/Low)
double pdh = iHigh(_Symbol, PERIOD_D1, 1);
double pdl = iLow(_Symbol, PERIOD_D1, 1);
if(pdh == 0 || pdl == 0) return; // Prevent execution if D1 data is not yet loaded
// 4. Fetch the Closed M15 Execution Candle
double m15Open = iOpen(_Symbol, PERIOD_M15, 1);
double m15High = iHigh(_Symbol, PERIOD_M15, 1);
double m15Low = iLow(_Symbol, PERIOD_M15, 1);
double m15Close = iClose(_Symbol, PERIOD_M15, 1);
// 5. Sweep Logic
bool bearishSweep = (m15High > pdh) && (m15Close < pdh) && (m15Open < pdh);
bool bullishSweep = (m15Low < pdl) && (m15Close > pdl) && (m15Open > pdl);
if(bearishSweep)
{
double hardStop = m15High;
double entryPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
// Exact Risk Sizing Math
double riskAmount = AccountInfoDouble(ACCOUNT_EQUITY) * (RiskPercent / 100.0);
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double stopLossTicks = (hardStop - entryPrice) / tickSize;
if(stopLossTicks <= 0) return;
double rawLots = riskAmount / (stopLossTicks * tickValue);
// Force lot sizes down to the broker's step interval (e.g., 0.01) so risk is strictly <= 1%
double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double lots = MathFloor(rawLots / lotStep) * lotStep;
if(lots >= minLot)
{
double tp = entryPrice - ((hardStop - entryPrice) * RiskRewardRatio);
trade.Sell(lots, _Symbol, entryPrice, hardStop, tp, "Sweep Short");
}
}
else if(bullishSweep)
{
double hardStop = m15Low;
double entryPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double riskAmount = AccountInfoDouble(ACCOUNT_EQUITY) * (RiskPercent / 100.0);
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double stopLossTicks = (entryPrice - hardStop) / tickSize;
if(stopLossTicks <= 0) return;
double rawLots = riskAmount / (stopLossTicks * tickValue);
double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double lots = MathFloor(rawLots / lotStep) * lotStep;
if(lots >= minLot)
{
double tp = entryPrice + ((entryPrice - hardStop) * RiskRewardRatio);
trade.Buy(lots, _Symbol, entryPrice, hardStop, tp, "Sweep Long");
}
}
}