preview
Larry Williams Market Secrets (Part 7): An Empirical Study of the Trade Day of the Week Concept

Larry Williams Market Secrets (Part 7): An Empirical Study of the Trade Day of the Week Concept

MetaTrader 5Experts |
247 0
Chacha Ian Maroa
Chacha Ian Maroa

Introduction

Most trading systems are built on price patterns, indicators, or volatility models. However, time is often treated as a neutral backdrop, something that merely passes while price does the real work. Trades are taken on Mondays the same way they are taken on Thursdays, as if markets express themselves uniformly across the calendar.

Larry Williams challenged this assumption decades ago. Through extensive observation and testing, he found that markets tend to behave differently on different days. Some days appear more responsive to breakout attempts, while others seem prone to failure or hesitation. This idea is simple, yet its implications are significant for short-term traders.

Rather than optimizing entries, exits, or risk management, this article takes a step back and asks a more basic question. If the same strategy is applied every day, do all days contribute equally to its results? Alternatively, do certain days quietly carry more weight than others? To explore this, we design a controlled experiment that removes unnecessary complexity. A single daily volatility-based entry is used, trades are held for one session only, and performance is evaluated purely on win rate. By stripping the system to its essentials, we allow the data to speak clearly.

The goal is not to build a profitable trading system, but to observe market behavior through the lens of time. In doing so, we lay the groundwork for a structured framework that traders can use to test, verify, and refine the Trade Day of the Week concept across any market.


The Trade Day of the Week Concept

Larry Williams observed that markets do not distribute opportunity evenly across time. In his research, price movement was not random when grouped by calendar days. Certain days showed a tendency toward stronger follow-through, while others more often led to stalled or failed moves. This behavior was not tied to a specific indicator or pattern, but to time itself.

The key insight is that time can act as a conditional filter. When a market is more likely to expand or trend on specific days, trades taken on those days carry a different probability profile than trades taken on less responsive days. Williams did not argue that a particular day guarantees success, but rather that some days statistically offer better conditions for short-term participation than others.

This idea becomes especially relevant in short-term trading systems. Such systems rely on limited holding periods and small margins of error. Even minor improvements in trade selection can materially affect outcomes. If a strategy performs the same way every day, it may be unintentionally averaging good conditions with poor ones. Filtering trades by day of the week can reduce exposure during periods that historically offer less favorable behavior, thereby improving overall efficiency without changing the core entry logic.

The Trade Day of the Week concept is well-suited for empirical testing because it is clearly defined, measurable, and repeatable. Days of the week are objective time categories that do not change across platforms or data sources. Each trading day can be classified unambiguously, and performance metrics such as win rate can be computed and compared directly. This makes the concept ideal for statistical analysis, walk-forward testing, and replication across different markets and time periods.

By isolating time as a variable and keeping the trading logic simple, it becomes possible to evaluate whether day-based bias exists and whether it persists over time. This approach aligns with Williams’ original emphasis on observation and verification rather than assumption, allowing the data to confirm or reject the presence of time-based market behavior.


Simplifying the Experiment

When testing a time-based market hypothesis, complexity quickly becomes a liability. The more conditions, filters, and management rules added to a system, the harder it becomes to identify what is actually driving the results. Since the objective of this study is to examine whether certain days consistently offer better trading conditions, all nonessential components must be stripped away.

For this reason, the experiment intentionally avoids standard trade management techniques, such as stop losses, take-profit targets, trailing stops, and partial exits. While these tools are essential in real trading, they introduce additional decision layers that can mask the influence of time. A stop loss hit, for example, may say more about intraday noise than about whether a particular day was favorable for directional movement.

Instead, each trade follows a single, uniform rule. A position is opened using Larry Williams’ volatility-based entry and held until the end of the trading day, when it is closed regardless of profit or loss. This ensures that every trade captures the full daily outcome and that results are directly comparable across all days of the week.

The entry logic itself is deliberately minimal. Rather than relying on swing confirmations or pattern recognition, the system uses the prior day’s range to project a breakout level from today’s open. This approach stays close to Williams’ original work while keeping the signal objective and easy to reproduce. The system either enters the market or it does not, removing ambiguity from signal interpretation.

By simplifying the structure in this way, the experiment isolates a single variable: time. Any observed difference in win rate between days can therefore be attributed to the day of the week rather than to trade management, indicator tuning, or discretionary filters. This creates a clean baseline that can later be expanded upon once the presence or absence of day-based bias has been established.


Building the Trade Day of the Week Test Expert Advisor

Before moving into implementation, it is important to clarify the expectations for this section. The goal here is not to present a finished black-box system, but to construct a controlled research tool that allows us to test Larry Williams’ Trade Day of the Week idea in a clean, reproducible way. Every component introduced serves a specific purpose and supports a logical step in the testing framework.

Prerequisites

To follow this section effectively, a few prerequisites are assumed.

First, we assume working familiarity with the MQL5 programming language. Core concepts such as variables, functions, conditional logic, loops, enumerations, structures, and the use of standard libraries should already be understood. If these foundations are still unclear, the official MQL5 reference provides an excellent starting point.

Second, prior experience with the MetaTrader 5 trading platform is required. We rely on basic platform operations such as opening charts, attaching Expert Advisors, navigating the Strategy Tester, and working with different timeframes.

Third, we assume comfort with MetaEditor. The ability to create new source files, write code, compile programs, and inspect compilation errors is essential for productive learning in this section.

To support hands-on learning, the completed Expert Advisor source code is provided as an attachment named lwTDWStudy.mq5. As we build the EA step by step, it is strongly encouraged to keep this file open in a separate tab for reference. Mastering programming concepts requires active engagement through comparison rather than passive consumption of material.

Creating the EA Foundation

We begin by creating a new empty Expert Advisor file in MetaEditor and pasting the initial boilerplate code.

//+------------------------------------------------------------------+
//|                                                   lwTDWStudy.mq5 |
//|          Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian |
//|                          https://www.mql5.com/en/users/chachaian |
//+------------------------------------------------------------------+

#property copyright "Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian"
#property link      "https://www.mql5.com/en/users/chachaian"
#property version   "1.00"

//+------------------------------------------------------------------+
//| Custom Enumerations                                              |
//+------------------------------------------------------------------+
enum ENUM_TDW_MODE
{
   TDW_ALL_DAYS,     
   TDW_SELECTED_DAYS
};

//+------------------------------------------------------------------+
//| Standard Libraries                                               |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>

//+------------------------------------------------------------------+
//| User input variables                                             |
//+------------------------------------------------------------------+
input group "Information"
input ulong magicNumber          = 254700680002;                 
input ENUM_TIMEFRAMES timeframe  = PERIOD_CURRENT;

input group "TDW filters"
input ENUM_TDW_MODE tradeDayMode = TDW_SELECTED_DAYS;
input bool tradeSunday           = false;
input bool tradeMonday           = true;
input bool tradeTuesday          = false;
input bool tradeWednesday        = false;
input bool tradeThursday         = false;
input bool tradeFriday           = false;
input bool tradeSaturday         = false;

input group "Volatility Breakout Parameters"
input double inpBuyRangeMultiplier = 0.50;

input group "Trade and Risk Management"
input double positionSize = 0.1;

//+------------------------------------------------------------------+
//| Global Variables                                                 |
//+------------------------------------------------------------------+
//--- Create a CTrade object to handle trading operations
CTrade Trade;

//--- To hep track current market prices for Buying (Ask) and Selling (Bid)
double askPrice;
double bidPrice;

//--- To store current time
datetime currentTime;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   //---  Assign a unique magic number to identify trades opened by this EA
   Trade.SetExpertMagicNumber(magicNumber);

   return(INIT_SUCCEEDED);
}

This foundation establishes metadata, includes required libraries, defines user inputs, and prepares global variables that will support all later logic.

The enumeration that defines the Trade Day of the Week mode is introduced early. It allows the EA to operate in two distinct configurations. One mode trades every day without filtering, serving as a baseline for comparison. The second mode restricts trading to user-selected days, enabling empirical testing of day-based bias.

The inclusion of the standard Trade library allows us to delegate order execution and position management to a robust, well-tested interface. This keeps the EA’s focus on research logic rather than low-level trade handling.

User inputs are grouped logically. Informational inputs define the magic number and working timeframe. Trade Day filters expose weekday selection controls. Volatility breakout parameters allow adjustment of the entry projection. Trade and risk inputs define position sizing. Each group reflects a distinct conceptual layer in the system.

Global variables are declared to track prices, time, and state. These variables form the shared memory through which all components of the EA communicate.

Detecting the Start of a New Trading Day

Since the experiment operates on a daily decision cycle, identifying the opening of a new bar is critical. For this purpose, we introduce a utility function that compares the timestamp of the most recent bar with a stored value.

//+------------------------------------------------------------------+
//| Function to check if there's a new bar on a given chart timeframe|
//+------------------------------------------------------------------+
bool IsNewBar(string symbol, ENUM_TIMEFRAMES tf, datetime &lastTm){

   datetime currentTm = iTime(symbol, tf, 0);
   if(currentTm != lastTm){
      lastTm       = currentTm;
      return true;
   }  
   return false;
   
}

The function receives the symbol, timeframe, and a reference to the last recorded bar open time. When a new bar is detected, the stored time is updated, and the function signals a state change. This mechanism ensures that daily calculations are performed exactly once per day, regardless of tick frequency.

To support this logic, a global datetime variable is declared and initialized during expert startup.

//--- To help track new bar open
datetime lastBarOpenTime;

Initializing it to zero guarantees that the first bar is detected correctly.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   ...
   
   //--- Initialize global variables
   lastBarOpenTime = 0;

   return(INIT_SUCCEEDED);
}

Representing Volatility Breakout Levels

Larry Williams’ volatility breakout logic requires two derived values: the previous day’s range and the projected entry level for the current day. Rather than managing these as isolated variables, we define a dedicated structure to hold both values.

//--- Holds all price levels derived from Larry Williams' volatility breakout calculations
struct MqlLwVolatilityLevels
{
   double yesterdayRange;      
   double buyEntryPrice;       
};

MqlLwVolatilityLevels lwVolatilityLevels;

This structure groups related data into a single logical unit, improving readability and reducing the risk of inconsistent state. An instance of this structure is declared globally and reset to zero during initialization to ensure a clean starting state.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   ...
   
   //--- Reset volatility levels 
   ZeroMemory(lwVolatilityLevels);

   return(INIT_SUCCEEDED);
}

Measuring the Previous Day’s Range

To compute daily volatility, we introduce a function that returns the range of a bar at a specified index. The function retrieves the high and low prices directly from historical data and returns their difference.

//+------------------------------------------------------------------+
//| Returns the price range (high - low) of a bar at the given index |
//+------------------------------------------------------------------+
double GetBarRange(const string symbol, ENUM_TIMEFRAMES tf, int index){

   double high = iHigh(symbol, tf, index);
   double low  = iLow (symbol, tf, index);

   if(high == 0.0 || low == 0.0){
      return 0.0;
   }

   return NormalizeDouble(high - low, Digits());
}

A defensive check ensures that invalid price values do not propagate through the system. Normalization aligns the result with the symbol’s precision. This function is reusable and keeps range calculation isolated from higher-level logic.

Projecting the Buy Entry Level

The breakout entry price is computed by adding a fraction of the previous day’s range to today’s open price. This calculation is encapsulated in a small, focused function that receives the required inputs and returns the projected price.

//+------------------------------------------------------------------+
//| Calculates the bullish breakout entry price using today's open and yesterday's range |
//+------------------------------------------------------------------+
double CalculateBuyEntryPrice(double todayOpen, double yesterdayRange, double buyMultiplier){

   return todayOpen + (yesterdayRange * buyMultiplier);
}

Isolating this logic makes the intent explicit and keeps the OnTick function free from arithmetic clutter.

Updating Daily Levels on Bar Open

With all supporting components in place, we integrate them inside the OnTick function.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){

   ...
   
   //--- Run this block only when a new bar is detected on the selected timeframe
   if(IsNewBar(_Symbol, timeframe, lastBarOpenTime)){
      lwVolatilityLevels.yesterdayRange = GetBarRange(_Symbol, timeframe, 1);
      lwVolatilityLevels.buyEntryPrice  = CalculateBuyEntryPrice (askPrice, lwVolatilityLevels.yesterdayRange, inpBuyRangeMultiplier );     
   }   
}

When a new daily bar is detected, the EA recalculates yesterday’s range and computes the buy entry price for the new day. At this exact moment, any active position is closed. In this experimental framework, the opening of a new day marks the end of the previous trade. This approach guarantees that each trade captures a full daily outcome and aligns with the study’s focus on day-based behavior rather than intraday management.

Tracking Intraday Price Movement

To detect when the price crosses the projected entry level, we monitor minute-level closing prices. A global array is defined to store recent one-minute close values.

//--- To store minutes data
double closePriceMinutesData [];

During expert initialization, the array is configured as a time series so that the most recent data is constantly accessible at index zero.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   ...
   
   //--- Treat the following arrays as timeseries (index 0 becomes the most recent bar)
   ArraySetAsSeries(closePriceMinutesData, true);

   return(INIT_SUCCEEDED);
}

On every tick, the array is updated using CopyClose.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){

   ...
   
   //--- Get some minutes data
   if(CopyClose(_Symbol, PERIOD_M1, 0, 5, closePriceMinutesData) == -1){
      Print("Error while copying minutes datas ", GetLastError());
      return;
   }   
}

This provides a rolling window of recent price behavior without excessive data processing.

Detecting Breakout Crossovers

The crossover detection logic checks whether the price has moved from below the projected level to above it between two consecutive minute closes. This definition ensures that entries are triggered only on genuine upward crossings, not on repeated touches.

//+------------------------------------------------------------------+
//| To detect a crossover at a given price level                     |                               
//+------------------------------------------------------------------+
bool IsCrossOver(const double price, const double &closePriceMinsData[]){
   if(closePriceMinsData[1] <= price && closePriceMinsData[0] > price){
      return true;
   }
   return false;
}

The function is deliberately simple. It answers a single question and returns a clear Boolean result. This simplicity makes the trading condition easy to audit and reason about.

Implementing Trade Day of the Week Filtering

To support the Trade Day of the Week concept, two helper functions are introduced. The first converts a datetime value into a numerical day of the week.

//+------------------------------------------------------------------------------------+
//| Returns the day of the week (0 = Sunday, 6 = Saturday) for the given datetime value|                               
//+------------------------------------------------------------------------------------+
int TimeDayOfWeek(datetime time){
   MqlDateTime timeStruct = {};
   if(!TimeToStruct(time, timeStruct)){
      Print("TimeDayOfWeek: TimeToStruct failed");
      return -1;
   }      
   return timeStruct.day_of_week;
}

The second evaluates whether trading is permitted based on the selected mode and user-defined weekday flags.

//+-----------------------------------------------------------------------------------------------------+
//| Determines whether trading is permitted for the given datetime based on the selected trade-day mode |                               
//+-----------------------------------------------------------------------------------------------------+
bool IsTradingDayAllowed(datetime time)
{
   // Baseline mode: no filtering
   if(tradeDayMode == TDW_ALL_DAYS){
      return true;
   }

   int day = TimeDayOfWeek(time);

   switch(day)
   {
      case 0: return tradeSunday;
      case 1: return tradeMonday;
      case 2: return tradeTuesday;
      case 3: return tradeWednesday;
      case 4: return tradeThursday;
      case 5: return tradeFriday;
      case 6: return tradeSaturday;
   }

   return false;
}

When the EA operates in baseline mode, trading is always allowed. When day filtering is enabled, the decision is delegated entirely to the weekday configuration. This separation ensures that the baseline experiment and the filtered experiment share identical execution logic, differing only in the timing of permissions.

Managing Positions Safely

Since the study allows only one active position at a time, a utility function is used to scan all open positions and verify whether a buy position belonging to the EA already exists.

//+------------------------------------------------------------------+
//| To verify whether this EA currently has an active buy position.  |                                 |
//+------------------------------------------------------------------+
bool IsThereAnActiveBuyPosition(ulong magic){
   
   for(int i = PositionsTotal() - 1; i >= 0; i--){
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0){
         Print("Error while fetching position ticket ", GetLastError());
         continue;
      }else{
         if(PositionGetInteger(POSITION_MAGIC) == magic && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY){
            return true;
         }
      }
   }
   
   return false;
}

The magic number ensures that only positions created by this EA instance are considered.

A second function handles position closure by magic number.

//+------------------------------------------------------------------+
//| To close all position with a specified magic number              |   
//+------------------------------------------------------------------+
void ClosePositionsByMagic(ulong magic) {
    
    for (int i = PositionsTotal() - 1; i >= 0; i--) {
        ulong ticket = PositionGetTicket(i);
        if (PositionSelectByTicket(ticket)) {
            if (PositionGetInteger(POSITION_MAGIC) == magic) {
                ulong positionType = PositionGetInteger(POSITION_TYPE);
                double volume = PositionGetDouble(POSITION_VOLUME);
                if (positionType == POSITION_TYPE_BUY) {
                    Trade.PositionClose(ticket);
                } else if (positionType == POSITION_TYPE_SELL) {
                    Trade.PositionClose(ticket);
                }
            }
        }
    }    
}

This is used at the start of each new trading day to exit the previous trade cleanly and consistently.

Executing Trades

Order execution is handled through a dedicated function that opens a market buy order with the specified lot size.

//+------------------------------------------------------------------+
//| Function to open a market buy position                           |
//+------------------------------------------------------------------+
bool OpenBuy(double entryPrice, double lotSize){
   if(!Trade.Buy(NormalizeDouble(lotSize, 2), _Symbol, entryPrice)){
      Print("Error while executing a market buy order: ", GetLastError());
      Print(Trade.ResultRetcode());
      Print(Trade.ResultComment());
      return false;
   }
   return true;
}

Errors are reported explicitly, making it easier to diagnose execution issues during testing. This function represents the final action in the decision chain and is called only when all prior conditions are satisfied.

Completing the Trading Logic

The final step is to integrate all conditions into the OnTick function. This EA is designed to hold trades for exactly one trading day: no stop loss, no take profit, no trailing logic. A trade must be closed at the end of the trading day, not earlier or later.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){

   ...
   
   //--- Run this block only when a new bar is detected on the selected timeframe
   if(IsNewBar(_Symbol, timeframe, lastBarOpenTime)){

      ...
      
      //--- Close any active long position
      if(IsThereAnActiveBuyPosition(magicNumber)){
         ClosePositionsByMagic(magicNumber);
      }    
   }   
}

The EA checks for price crossover above the projected entry level. If baseline mode is active, the trade is executed immediately. If day filtering is enabled, the crossover must also occur on an allowed trading day.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){

   ...
   
   if(tradeDayMode == TDW_ALL_DAYS){
      if(IsCrossOver(lwVolatilityLevels.buyEntryPrice, closePriceMinutesData )){
         OpenBuy(askPrice, positionSize);
      }
   }
   
   if(tradeDayMode == TDW_SELECTED_DAYS){
      if(IsTradingDayAllowed(currentTime)){
         if(IsCrossOver(lwVolatilityLevels.buyEntryPrice, closePriceMinutesData)){
            OpenBuy(askPrice, positionSize);
         }
      }
   }   
}

Here is the final form of the OnTick function after all components have been implement:

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){

   //--- Retrieve current market prices for trade execution
   askPrice      = SymbolInfoDouble (_Symbol, SYMBOL_ASK);
   bidPrice      = SymbolInfoDouble (_Symbol, SYMBOL_BID); 
   
   //--- Run this block only when a new bar is detected on the selected timeframe
   if(IsNewBar(_Symbol, timeframe, lastBarOpenTime)){
   
      UpdateSupertrendBandValues();
      
      if(IsSupertrendBullishSignal()){   
         if(IsThereAnActiveSellPosition(magicNumber)){
            ClosePositionsByMagic(magicNumber);
            Sleep(50);
         }
         if(direction == TRADE_BOTH || direction == ONLY_LONG){
            OpenBuy(askPrice, CalculateAdaptiveStopLossPrice(POSITION_TYPE_BUY), positionSize);
         }
      }
      
      if(IsSupertrendBearishSignal()){
         if(IsThereAnActiveBuyPosition(magicNumber)){
            ClosePositionsByMagic(magicNumber);
            Sleep(50);
         }
         if(direction == TRADE_BOTH || direction == ONLY_SHORT){
            OpenSel(bidPrice, CalculateAdaptiveStopLossPrice(POSITION_TYPE_SELL), positionSize);
         }
      }      
   }   
}

Before we move to testing, we need to ensure the chart environment clearly presents price action and trade activity. A clean and consistent chart layout makes it much easier to visually inspect entries, exits, and overall behavior during strategy testing. Since this Expert Advisor is intended for research and analysis, improving chart readability is a small but important step.

To achieve this, we define a custom utility function that configures the chart appearance when the Expert Advisor is defined. This function applies a set of visual preferences so that candles, background, and price movements are easy to distinguish during testing and replay. Below is the function definition, which should be placed in the section reserved for custom MQL5 functions.

//+------------------------------------------------------------------+
//| This function configures the chart's appearance.                 |
//+------------------------------------------------------------------+
bool ConfigureChartAppearance()
{
   if(!ChartSetInteger(0, CHART_COLOR_BACKGROUND, clrWhite)){
      Print("Error while setting chart background, ", GetLastError());
      return false;
   }
   
   if(!ChartSetInteger(0, CHART_SHOW_GRID, false)){
      Print("Error while setting chart grid, ", GetLastError());
      return false;
   }
   
   if(!ChartSetInteger(0, CHART_MODE, CHART_CANDLES)){
      Print("Error while setting chart mode, ", GetLastError());
      return false;
   }

   if(!ChartSetInteger(0, CHART_COLOR_FOREGROUND, clrBlack)){
      Print("Error while setting chart foreground, ", GetLastError());
      return false;
   }

   if(!ChartSetInteger(0, CHART_COLOR_CANDLE_BULL, clrSeaGreen)){
      Print("Error while setting bullish candles color, ", GetLastError());
      return false;
   }
      
   if(!ChartSetInteger(0, CHART_COLOR_CANDLE_BEAR, clrBlack)){
      Print("Error while setting bearish candles color, ", GetLastError());
      return false;
   }
   
   if(!ChartSetInteger(0, CHART_COLOR_CHART_UP, clrSeaGreen)){
      Print("Error while setting bearish candles color, ", GetLastError());
      return false;
   }
   
   if(!ChartSetInteger(0, CHART_COLOR_CHART_DOWN, clrBlack)){
      Print("Error while setting bearish candles color, ", GetLastError());
      return false;
   }
   
   return true;
}

The function works by calling a series of ChartSetInteger commands. Each command modifies a specific visual property of the currently active chart.

First, the chart background color is set to white. A light background improves contrast and makes candle colors stand out clearly. Next, the chart grid is disabled. Removing the grid reduces visual noise and keeps the focus on price action rather than auxiliary lines. The chart mode is then set to candlestick view. Candlesticks provide more information than line charts and are better suited for analyzing volatility, structure, and intraday behavior.

After that, the foreground color is set to black. This ensures that chart text and price scales remain clearly visible against the white background. The function then defines distinct colors for bullish and bearish candles. Bullish candles are colored sea green to highlight upward price movement, while bearish candles are colored black to maintain a neutral and readable contrast. The same color logic is applied to the chart bar outlines for upward and downward movement. This keeps candle bodies and outlines visually consistent and easy to interpret.

Each ChartSetInteger call is checked for success. If any configuration step fails, an error message is logged, and the function returns false immediately. This allows the Expert Advisor to detect configuration problems early and avoid running under unintended chart conditions. If all chart settings are successfully applied, the function returns true, indicating that the chart is ready for testing and analysis.

Once the function is defined, it is called from within the expert initialization function. This ensures that the chart appearance is configured once, right when the Expert Advisor starts running.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   ...
   
   //--- To configure the chart's appearance
   if(!ConfigureChartAppearance()){
      Print("Error while configuring chart appearance", GetLastError());
      return INIT_FAILED;
   }

   return(INIT_SUCCEEDED);
}

Inside the OnInit function, we call the chart configuration routine and verify its result. If the configuration fails, the Expert Advisor stops initialization and reports the issue. If it succeeds, initialization continues normally.

This approach ensures that every test starts with a clean, readable chart layout, making it easier to evaluate trade behavior, review historical performance, and visually confirm that the strategy's logic behaves as intended during testing.

At this point, the EA logic is complete. Every component introduced earlier now fits into a coherent execution flow that precisely reflects the research objective.

This section walks through the construction of a purpose-built Expert Advisor designed to test the Trade Day of the Week hypothesis. The design emphasizes clarity, variable isolation, and reproducibility. Each function serves a specific role and supports a clean separation between daily decision-making, intraday execution, and time-based filtering.

The completed source code is provided as lwTDWStudy.mq5 and can be used directly for testing or extended further for additional experiments. With the EA in place, we are now prepared to move from implementation to empirical evaluation and begin analyzing whether certain days truly offer a measurable trading advantage.


Empirical Testing of the Trade Day of the Week Filter

To investigate the Trade Day of the Week hypothesis, a series of controlled experiments was conducted on Gold (XAUUSD) using the Daily (D1) timeframe. The objective was to determine whether filtering trades by day of the week produces measurable differences in performance.

Two experiment types were used:

1. Baseline Tests

These tests allow the strategy to trade on any day of the week whenever the entry condition is met. No time-based filtering is applied. This establishes a neutral reference point.

2. Trade Day of the Week Tests

These tests restrict trading to one specific day of the week at a time, allowing performance to be evaluated independently for each day. All tests were performed using walk-forward quarterly segmentation, ensuring that a single favorable market phase does not drive results.

Baseline Performance Without Day Filtering

The baseline experiment was run over the whole calendar year.

Test Configuration:

  • Period: 1 January 2025 to 30 December 2025
  • tradeDayMode: TDW_ALL_DAYS
  • Trades allowed on all trading days

Results:

Metric Value
Win Rate 54.25%
Net Profit $26102.15

Quarterly Walk-Forward Results by Trading Day

Each quarter was tested independently using TDW_SELECTED_DAYS. Only one day of the week was enabled at a time, and results were recorded.

Quarter 1 Results:

1 January 2025 – 31 March 2025

Day Win Rate (%) Net Profit ($)
Monday 77.00 4444.24
Tuesday 59.35 93344.24
Wednesday 64.22 -14112.00
Thursday 57.43 9883.21
Friday 72.45 -1280.82
Baseline 59.64 26102.15

Observation:

Not all high win rates translate into profitability. Wednesday and Friday show respectable accuracy but negative returns, highlighting the importance of pairing win rate with payoff characteristics.

Quarter 2 Results:

1 April 2025 – 30 June 2025

Day Win Rate (%) Net Profit ($)
Monday 100.00 33137.25
Tuesday 0.00 -21054.39
Wednesday 92.31 44388.16
Thursday 23.53 -13790.47
Friday 61.40 17674.23
Baseline 61.16 48514.81

Observation:

This quarter shows extreme day-to-day divergence. Wednesday dominates both in accuracy and profitability, while Tuesday completely fails. Such dispersion is inconsistent with the random-market assumption.

Quarter 3 Results:

1 July 2025 – 30 September 2025

Day Win Rate (%) Net Profit ($)
Monday 92.787 32767.01
Tuesday 13.95 -13797.71
Wednesday 5.91 -9466.48
Thursday 54.10 -4330.74
Friday 58.18 16728.25
Baseline 52.41 28616.31

Observation:

Monday and Friday stand out, while mid-week trading performs poorly. Again, day-specific behavior dominates performance outcomes.

Quarter 4 Results:

1 October 2025 – 30 December 2025

Day Win Rate (%) Net Profit ($)
Monday 61.38 20288.15
Tuesday 0.00 -4677.96
Wednesday 60.32 -31755.28
Thursday 42.59 3169.84
Friday 22.88 -2059.73
Baseline 64.27 -1101.06

Observation:

The baseline itself becomes unprofitable in this quarter, while selective day trading remains viable. Monday continues to show resilience across market conditions.

What the Numbers Are Telling Us

Several conclusions emerge clearly from the data:

Performance is not evenly distributed across the week. Certain days consistently outperform others, while others repeatedly fail to meet expectations. Win rate alone is insufficient. Some days achieve high accuracy but generate losses, reinforcing the need to evaluate profitability alongside win rate. Day filtering can reduce exposure to structurally weak periods

Excluding underperforming days improves stability without changing the core strategy logic. The market exhibits time-based behavioral bias. The repeated quarterly patterns strongly support Larry Williams’ assertion that trading every day equally sacrifices a measurable edge.

Rather than predicting direction, the Trade Day of the Week filter functions as a probabilistic lens, guiding traders toward periods when opportunity is more likely and away from days when risk outweighs reward.


Conclusion

This study set out to examine an often-ignored yet straightforward idea: that time itself may offer an edge in short-term trading. By translating Larry Williams’ Trade Day of the Week concept into a measurable, testable framework, we moved the discussion from opinion to evidence.

Through controlled baseline testing and quarterly walk-forward experiments on Gold, we demonstrated that trading performance is not evenly distributed across the week. Some days consistently delivered higher win rates and stronger profitability, while others repeatedly eroded expectancy. These differences persisted across multiple market phases, challenging the assumption that all trading days behave the same.

More importantly, this article did not stop at results. It showed how such time-based biases can be investigated objectively using MQL5. The Expert Advisor design, input structure, and testing methodology form a reusable foundation that readers can adapt to other markets, timeframes, or filtering criteria. While the focus here was on profitability and performance, the same framework can be extended to study volatility, range expansion, drawdown behavior, and intraday trading.

By the end of this article, the reader gains more than confirmation that some days are better than others. They gain a practical research blueprint. One that encourages selective participation, disciplined filtering, and deeper exploration of market behavior rather than blind execution.

For traders and developers alike, this work reinforces a simple idea with meaningful consequences. If markets exhibit time-based tendencies, then ignoring them is a choice. Measuring them is an advantage. 

Attached files |
lwTDWStudy.mq5 (12.34 KB)
Price Action Analysis Toolkit Development (Part 56): Reading Session Acceptance and Rejection with CPI Price Action Analysis Toolkit Development (Part 56): Reading Session Acceptance and Rejection with CPI
This article presents a session-based analytical framework that combines time-defined market sessions with the Candle Pressure Index (CPI) to classify acceptance and rejection behavior at session boundaries using closed-candle data and clearly defined rules.
Developing Trend Trading Strategies Using Machine Learning Developing Trend Trading Strategies Using Machine Learning
This study introduces a novel methodology for the development of trend-following trading strategies. This section describes the process of annotating training data and using it to train classifiers. This process yields fully operational trading systems designed to run on MetaTrader 5.
Risk Management (Part 3): Building the Main Class for Risk Management Risk Management (Part 3): Building the Main Class for Risk Management
In this article, we will begin creating a core risk management class that will be key to controlling risks in the system. We will focus on building the foundations, defining the basic structures, variables and functions. In addition, we will implement the necessary methods for setting maximum profit and loss values, thereby laying the foundation for risk management.
Neural Networks in Trading: Hybrid Graph Sequence Models (GSM++) Neural Networks in Trading: Hybrid Graph Sequence Models (GSM++)
Hybrid graph sequence models (GSM++) combine the advantages of different architectures to provide high-fidelity data analysis and optimized computational costs. These models adapt effectively to dynamic market data, improving the presentation and processing of financial information.