Advertisement IC Markets

Session budgets for discretionary scalpers: beginner mistakes

Discuss 1-minute to 15-minute price action setups, fading intraday momentum, key support/resistance zones, and proven short-term trading methodologies.
Post Reply
LondonScalper
Posts: 701
Joined: Sat Sep 05, 2026 7:54 am

Session budgets for discretionary scalpers: beginner mistakes

Post by LondonScalper »

Session budgets — beginner mistakes I still see

A session budget is not “I feel like trading three hours.” It is a pre-committed cap on risk, trade count, and clock so the day cannot quietly expand. Beginners (and tired pros) usually fail the same ways:
  • Budget in hours only — ignore R, then eight scratches “fit” the clock
  • One shared budget for London + NY — the second session steals the first’s leftover risk
  • Moving the budget after a win (“I earned more trades”)
  • No cost awareness — ten micro-trades that are really a death by spread
What worked when I mentored newer desks: write the budget before the open, screenshot it, and end-of-day compare. Green days that broke budget still count as process fails.

What does your session budget include — R, trades, pairs, or all three? And what is the most common way you personally cheat it? Write it down where you can see it while the platform is open. A budget in a notebook you never open mid-session is theatre.
Recommended broker for automated trading & scalping IC Markets
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Session budgets for discretionary scalpers: beginner mistakes

Post by PTScalper »

LondonScalper wrote: Fri Sep 18, 2026 5:27 pm Session budgets — beginner mistakes I still see

A session budget is not “I feel like trading three hours.” It is a pre-committed cap on risk, trade count, and clock so the day cannot quietly expand. Beginners (and tired pros) usually fail the same ways:
  • Budget in hours only — ignore R, then eight scratches “fit” the clock
  • One shared budget for London + NY — the second session steals the first’s leftover risk
  • Moving the budget after a win (“I earned more trades”)
  • No cost awareness — ten micro-trades that are really a death by spread
What worked when I mentored newer desks: write the budget before the open, screenshot it, and end-of-day compare. Green days that broke budget still count as process fails.

What does your session budget include — R, trades, pairs, or all three? And what is the most common way you personally cheat it? Write it down where you can see it while the platform is open. A budget in a notebook you never open mid-session is theatre.
Hi LondonScalper,

Your assessment of "green days that broke budget still count as process fails" is the exact dividing line between amateurs and professionals. If the process is compromised, the profit is just a short-term loan from the market that it will eventually claw back with interest.

To answer your questions directly:

A structural session budget must include all three (Risk, Trades, and Pairs), but they must be completely siloed by session.

Risk (R): A hard cap on session drawdown (e.g., -2R). If London hits -2R, the platform is closed until New York. London's losses do not get subsidized by New York's budget.

Trade Count: A hard limit (e.g., 3-4 trades per session). This forces extreme selectivity. If you know you only have three "bullets" for the NY open, you stop firing at low-probability, low-liquidity chop.

Pairs: Limit to 1 or 2 highly liquid assets (e.g., EURUSD and Gold). Watching 8 pairs breeds FOMO and guarantees you will take a suboptimal setup just because it's moving.

The most common way to cheat the budget:

The "fractional risk loophole." When nearing the max trade limit or max drawdown, the psychological trick is to cut the lot size in half and say, "I'm only risking 0.25R, so this doesn't really count against the budget." It is a complete compromise of the process. It leads to the exact "death by spread" scenario you mentioned—churning out micro-trades just to satisfy the need to click buttons, rather than executing an edge.

You noted that a budget hidden in a notebook is just theatre. It needs to be written where you can see it while the platform is open.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Session budgets for discretionary scalpers: beginner mistakes

Post by PTScalper »

Here is a Pine Script v5 indicator that acts as an On-Chart Session Enforcer. It paints your active trading windows (to keep the clock strict) and locks a permanent dashboard to the bottom right of your chart so your budget is staring you in the face while you trade.

Code: Select all

//@version=5
indicator("Session Budget Enforcer", overlay=true)

// =========================================================================
// INPUTS: Session Windows
// =========================================================================
grp_time    = "1. Strict Time Caps"
london_sess = input.session("0800-1130", title="London Session", group=grp_time)
ny_sess     = input.session("1330-1630", title="New York Session", group=grp_time)
tz          = input.string("UTC+1", title="Timezone", group=grp_time)

// =========================================================================
// INPUTS: Budget Rules
// =========================================================================
grp_budget = "2. Session Budget Limits"
max_risk   = input.float(2.0, title="Max Risk Cap (R or %)", step=0.5, group=grp_budget)
max_trades = input.int(3, title="Max Trades Per Session", minval=1, group=grp_budget)
max_pairs  = input.string("EURUSD, XAUUSD", title="Allowed Assets", group=grp_budget)

// =========================================================================
// SESSION LOGIC & BACKGROUNDS
// =========================================================================
in_london = time(timeframe.period, london_sess, tz) != 0
in_ny     = time(timeframe.period, ny_sess, tz) != 0

// Paint the chart background to enforce the "Clock" rule
bgcolor(in_london ? color.new(color.blue, 92) : na, title="London Background")
bgcolor(in_ny ? color.new(color.orange, 92) : na, title="NY Background")

// =========================================================================
// DASHBOARD (The "Don't Cheat" Visualizer)
// =========================================================================
var table budget_board = table.new(position.bottom_right, columns=2, rows=6, bgcolor=color.new(color.black, 70), border_width=1, border_color=color.new(color.gray, 50))

if barstate.islast
    // Header
    table.cell(budget_board, 0, 0, "SESSION BUDGET", text_color=color.white, text_halign=text.align_left, bgcolor=color.new(color.gray, 50))
    table.cell(budget_board, 1, 0, "", bgcolor=color.new(color.gray, 50))

    // Active Session Status
    table.cell(budget_board, 0, 1, "Active Window:", text_color=color.silver, text_halign=text.align_left)
    
    string session_name = "OUT OF SESSION"
    color  session_col  = color.red
    if in_london
        session_name := "LONDON"
        session_col  := color.aqua
    else if in_ny
        session_name := "NEW YORK"
        session_col  := color.orange
        
    table.cell(budget_board, 1, 1, session_name, text_color=session_col, text_halign=text.align_right)

    // Rule 1: Risk
    table.cell(budget_board, 0, 2, "Max Risk Cap:", text_color=color.silver, text_halign=text.align_left)
    table.cell(budget_board, 1, 2, str.tostring(max_risk) + " R", text_color=color.yellow, text_halign=text.align_right)

    // Rule 2: Trades
    table.cell(budget_board, 0, 3, "Trade Limit:", text_color=color.silver, text_halign=text.align_left)
    table.cell(budget_board, 1, 3, str.tostring(max_trades), text_color=color.yellow, text_halign=text.align_right)

    // Rule 3: Pairs
    table.cell(budget_board, 0, 4, "Allowed Assets:", text_color=color.silver, text_halign=text.align_left)
    table.cell(budget_board, 1, 4, max_pairs, text_color=color.yellow, text_halign=text.align_right)

    // Warning Banner
    bool is_trading_time = in_london or in_ny
    string banner_text = is_trading_time ? "STICK TO THE PLAN" : "HANDS OFF KEYBOARD"
    color banner_color = is_trading_time ? color.lime : color.red
    
    table.cell(budget_board, 0, 5, banner_text, text_color=banner_color, text_halign=text.align_center, text_size=size.small)
    table.merge_cells(budget_board, 0, 5, 1, 5)
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Session budgets for discretionary scalpers: beginner mistakes

Post by PTScalper »

Both MetaTrader 4 and MetaTrader 5 rely on OBJ_LABEL for fixed on-screen dashboards. Unlike Pine Script’s table functions, we have to draw and position the text lines individually.

Because we want the dashboard to update exactly when a session opens or closes—even if the market is dead and no new price ticks are coming in—both indicators run on an independent 1-second timer via OnTimer().

MQL4 Indicator (Session_Enforcer_MT4.mq4)

Code: Select all

//+------------------------------------------------------------------+
//|                                         Session_Enforcer_MT4.mq4 |
//|                             On-chart visual budget accountability |
//+------------------------------------------------------------------+
#property copyright "Your Custom Tool"
#property indicator_chart_window
#property indicator_buffers 0

//--- Inputs
input string   LondonStart   = "08:00"; // London Start Time (Broker Time)
input string   LondonEnd     = "11:30"; // London End Time
input string   NYStart       = "13:30"; // NY Start Time
input string   NYEnd         = "16:30"; // NY End Time
input double   MaxRisk       = 2.0;     // Max Risk Cap (R or %)
input int      MaxTrades     = 3;       // Max Trades Per Session
input string   AllowedAssets = "EURUSD, XAUUSD"; // Allowed Assets

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit() {
    EventSetTimer(1); // Update clock every 1 second
    DrawStaticDashboard();
    UpdateDashboard(); // Initial run
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
    EventKillTimer();
    ObjectsDeleteAll(0, "Budg_");
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total, const int prev_calculated, 
                const datetime &time[], const double &open[], 
                const double &high[], const double &low[], 
                const double &close[], const long &tick_volume[], 
                const long &volume[], const int &spread[]) {
    return(rates_total);
}

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer() {
    UpdateDashboard();
}

//+------------------------------------------------------------------+
//| Session & Dashboard Logic                                        |
//+------------------------------------------------------------------+
bool IsInSession(string start_str, string end_str) {
    datetime now = TimeCurrent();
    string today = TimeToString(now, TIME_DATE);
    datetime start_time = StringToTime(today + " " + start_str);
    datetime end_time = StringToTime(today + " " + end_str);
    
    // Handle sessions that span across midnight
    if (end_time < start_time) {
        end_time += PeriodSeconds(PERIOD_D1);
        if (now < start_time) { 
            start_time -= PeriodSeconds(PERIOD_D1);
            end_time -= PeriodSeconds(PERIOD_D1);
        }
    }
    return (now >= start_time && now <= end_time);
}

void CreateLabel(string name, string text, int x, int y, color col, int fontSize = 10, bool isValue = false) {
    ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
    ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
    ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
    ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
    ObjectSetString(0, name, OBJPROP_TEXT, text);
    ObjectSetString(0, name, OBJPROP_FONT, "Trebuchet MS");
    ObjectSetInteger(0, name, OBJPROP_COLOR, col);
    ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontSize);
    
    // Anchor values to the right, labels to the right with offset
    ObjectSetInteger(0, name, OBJPROP_ANCHOR, isValue ? ANCHOR_RIGHT_LOWER : ANCHOR_RIGHT_LOWER);
}

void DrawStaticDashboard() {
    int lbl_x = 150; // Left column X
    int val_x = 10;  // Right column X
    
    CreateLabel("Budg_Title", "--- SESSION BUDGET ---", val_x, 150, clrWhite, 10, true);
    
    CreateLabel("Budg_Lbl_Window", "Active Window:", lbl_x, 120, clrSilver, 10);
    CreateLabel("Budg_Val_Window", "INIT", val_x, 120, clrGray, 10, true);
    
    CreateLabel("Budg_Lbl_Risk", "Max Risk Cap:", lbl_x, 95, clrSilver, 10);
    CreateLabel("Budg_Val_Risk", DoubleToString(MaxRisk, 1) + " R", val_x, 95, clrYellow, 10, true);
    
    CreateLabel("Budg_Lbl_Trades", "Trade Limit:", lbl_x, 70, clrSilver, 10);
    CreateLabel("Budg_Val_Trades", IntegerToString(MaxTrades), val_x, 70, clrYellow, 10, true);
    
    CreateLabel("Budg_Lbl_Assets", "Allowed Assets:", lbl_x, 45, clrSilver, 10);
    CreateLabel("Budg_Val_Assets", AllowedAssets, val_x, 45, clrYellow, 10, true);
    
    CreateLabel("Budg_Warning", "INIT", val_x, 15, clrGray, 11, true);
}

void UpdateDashboard() {
    bool inLondon = IsInSession(LondonStart, LondonEnd);
    bool inNY = IsInSession(NYStart, NYEnd);
    
    string activeWindow = "OUT OF SESSION";
    color windowColor = clrRed;
    string warningText = "HANDS OFF KEYBOARD";
    color warningColor = clrRed;
    
    if(inLondon) {
        activeWindow = "LONDON";
        windowColor = clrAqua;
        warningText = "STICK TO THE PLAN";
        warningColor = clrLime;
    } else if(inNY) {
        activeWindow = "NEW YORK";
        windowColor = clrOrange;
        warningText = "STICK TO THE PLAN";
        warningColor = clrLime;
    }
    
    ObjectSetString(0, "Budg_Val_Window", OBJPROP_TEXT, activeWindow);
    ObjectSetInteger(0, "Budg_Val_Window", OBJPROP_COLOR, windowColor);
    
    ObjectSetString(0, "Budg_Warning", OBJPROP_TEXT, warningText);
    ObjectSetInteger(0, "Budg_Warning", OBJPROP_COLOR, warningColor);
    
    ChartRedraw();
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Session budgets for discretionary scalpers: beginner mistakes

Post by PTScalper »

MQL5 Indicator (Session_Enforcer_MT5.mq5)

The MT5 version uses the exact same drawing logic but requires strict #property indicator_plots 0 so the engine does not look for graphical buffers.

Code: Select all

//+------------------------------------------------------------------+
//|                                         Session_Enforcer_MT5.mq5 |
//|                             On-chart visual budget accountability |
//+------------------------------------------------------------------+
#property copyright "Your Custom Tool"
#property indicator_chart_window
#property indicator_plots 0

//--- Inputs
input string   LondonStart   = "08:00"; // London Start Time (Broker Time)
input string   LondonEnd     = "11:30"; // London End Time
input string   NYStart       = "13:30"; // NY Start Time
input string   NYEnd         = "16:30"; // NY End Time
input double   MaxRisk       = 2.0;     // Max Risk Cap (R or %)
input int      MaxTrades     = 3;       // Max Trades Per Session
input string   AllowedAssets = "EURUSD, XAUUSD"; // Allowed Assets

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit() {
    EventSetTimer(1); // Update clock every 1 second
    DrawStaticDashboard();
    UpdateDashboard(); // Initial run
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
    EventKillTimer();
    ObjectsDeleteAll(0, "Budg_");
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total, const int prev_calculated, 
                const datetime &time[], const double &open[], 
                const double &high[], const double &low[], 
                const double &close[], const long &tick_volume[], 
                const long &volume[], const int &spread[]) {
    return(rates_total);
}

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer() {
    UpdateDashboard();
}

//+------------------------------------------------------------------+
//| Session & Dashboard Logic                                        |
//+------------------------------------------------------------------+
bool IsInSession(string start_str, string end_str) {
    datetime now = TimeCurrent();
    string today = TimeToString(now, TIME_DATE);
    datetime start_time = StringToTime(today + " " + start_str);
    datetime end_time = StringToTime(today + " " + end_str);
    
    // Handle sessions that span across midnight
    if (end_time < start_time) {
        end_time += PeriodSeconds(PERIOD_D1);
        if (now < start_time) { 
            start_time -= PeriodSeconds(PERIOD_D1);
            end_time -= PeriodSeconds(PERIOD_D1);
        }
    }
    return (now >= start_time && now <= end_time);
}

void CreateLabel(string name, string text, int x, int y, color col, int fontSize = 10, bool isValue = false) {
    ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
    ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
    ObjectSetInteger(0, name, OBJ, OBJPROP_XDISTANCE, x);
    ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
    ObjectSetString(0, name, OBJPROP_TEXT, text);
    ObjectSetString(0, name, OBJPROP_FONT, "Trebuchet MS");
    ObjectSetInteger(0, name, OBJPROP_COLOR, col);
    ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontSize);
    
    // Anchor values to the right, labels to the right with offset
    ObjectSetInteger(0, name, OBJPROP_ANCHOR, isValue ? ANCHOR_RIGHT_LOWER : ANCHOR_RIGHT_LOWER);
}

void DrawStaticDashboard() {
    int lbl_x = 150; // Left column X
    int val_x = 10;  // Right column X
    
    CreateLabel("Budg_Title", "--- SESSION BUDGET ---", val_x, 150, clrWhite, 10, true);
    
    CreateLabel("Budg_Lbl_Window", "Active Window:", lbl_x, 120, clrSilver, 10);
    CreateLabel("Budg_Val_Window", "INIT", val_x, 120, clrGray, 10, true);
    
    CreateLabel("Budg_Lbl_Risk", "Max Risk Cap:", lbl_x, 95, clrSilver, 10);
    CreateLabel("Budg_Val_Risk", DoubleToString(MaxRisk, 1) + " R", val_x, 95, clrYellow, 10, true);
    
    CreateLabel("Budg_Lbl_Trades", "Trade Limit:", lbl_x, 70, clrSilver, 10);
    CreateLabel("Budg_Val_Trades", IntegerToString(MaxTrades), val_x, 70, clrYellow, 10, true);
    
    CreateLabel("Budg_Lbl_Assets", "Allowed Assets:", lbl_x, 45, clrSilver, 10);
    CreateLabel("Budg_Val_Assets", AllowedAssets, val_x, 45, clrYellow, 10, true);
    
    CreateLabel("Budg_Warning", "INIT", val_x, 15, clrGray, 11, true);
}

void UpdateDashboard() {
    bool inLondon = IsInSession(LondonStart, LondonEnd);
    bool inNY = IsInSession(NYStart, NYEnd);
    
    string activeWindow = "OUT OF SESSION";
    color windowColor = clrRed;
    string warningText = "HANDS OFF KEYBOARD";
    color warningColor = clrRed;
    
    if(inLondon) {
        activeWindow = "LONDON";
        windowColor = clrAqua;
        warningText = "STICK TO THE PLAN";
        warningColor = clrLime;
    } else if(inNY) {
        activeWindow = "NEW YORK";
        windowColor = clrOrange;
        warningText = "STICK TO THE PLAN";
        warningColor = clrLime;
    }
    
    ObjectSetString(0, "Budg_Val_Window", OBJPROP_TEXT, activeWindow);
    ObjectSetInteger(0, "Budg_Val_Window", OBJPROP_COLOR, windowColor);
    
    ObjectSetString(0, "Budg_Warning", OBJPROP_TEXT, warningText);
    ObjectSetInteger(0, "Budg_Warning", OBJPROP_COLOR, warningColor);
    
    ChartRedraw();
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Session budgets for discretionary scalpers: beginner mistakes

Post by PTScalper »

Note on Times: The inputs LondonStart, LondonEnd, etc., must be configured to your specific Broker Server Time (not your local Czech time). MetaTrader's TimeCurrent() pulls directly from the broker's clock. If your broker runs on EET (UTC+2/UTC+3), adjust the default hour strings accordingly.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Session budgets for discretionary scalpers: beginner mistakes

Post by PTScalper »

This allows us to build a clean, responsive dashboard that docks securely to the chart and natively updates via the OnTimer() override without fighting the chart rendering engine.

Here is the C# source for cTrader:

Code: Select all

using System;
using cAlgo.API;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SessionBudgetEnforcer : Indicator
    {
        // --- Parameters ---
        [Parameter("London Start", DefaultValue = "08:00", Group = "1. Strict Time Caps")]
        public string LondonStartStr { get; set; }

        [Parameter("London End", DefaultValue = "11:30", Group = "1. Strict Time Caps")]
        public string LondonEndStr { get; set; }

        [Parameter("NY Start", DefaultValue = "13:30", Group = "1. Strict Time Caps")]
        public string NYStartStr { get; set; }

        [Parameter("NY End", DefaultValue = "16:30", Group = "1. Strict Time Caps")]
        public string NYEndStr { get; set; }

        [Parameter("Max Risk Cap (R or %)", DefaultValue = 2.0, Group = "2. Session Budget Limits")]
        public double MaxRisk { get; set; }

        [Parameter("Max Trades Per Session", DefaultValue = 3, Group = "2. Session Budget Limits")]
        public int MaxTrades { get; set; }

        [Parameter("Allowed Assets", DefaultValue = "EURUSD, XAUUSD", Group = "2. Session Budget Limits")]
        public string AllowedAssets { get; set; }

        // --- Internal Variables ---
        private TimeSpan _londonStart, _londonEnd, _nyStart, _nyEnd;
        private TextBlock _windowValueTextBlock;
        private TextBlock _warningTextBlock;

        protected override void Initialize()
        {
            // Parse inputs into native C# TimeSpans
            TimeSpan.TryParse(LondonStartStr, out _londonStart);
            TimeSpan.TryParse(LondonEndStr, out _londonEnd);
            TimeSpan.TryParse(NYStartStr, out _nyStart);
            TimeSpan.TryParse(NYEndStr, out _nyEnd);

            BuildDashboard();
            
            // Fire the timer every 1 second independent of incoming price ticks
            Timer.Start(TimeSpan.FromSeconds(1));
        }

        public override void Calculate(int index)
        {
            // Indicator logic is entirely UI and time-based; no per-tick array calculation needed.
        }

        protected override void OnTimer()
        {
            UpdateDashboard();
        }

        private void BuildDashboard()
        {
            var mainPanel = new StackPanel 
            { 
                Orientation = Orientation.Vertical, 
                Margin = new Thickness(12) 
            };
            
            var dashboardBorder = new Border
            {
                BackgroundColor = Color.FromArgb(220, 25, 25, 25),
                BorderColor = Color.FromArgb(255, 60, 60, 60),
                BorderThickness = new Thickness(1),
                CornerRadius = 3,
                HorizontalAlignment = HorizontalAlignment.Right,
                VerticalAlignment = VerticalAlignment.Bottom,
                Margin = new Thickness(0, 0, 60, 40), // Offsets to avoid overlapping cTrader's native chart buttons
                Child = mainPanel
            };

            // Title
            mainPanel.AddChild(new TextBlock 
            { 
                Text = "--- SESSION BUDGET ---", 
                ForegroundColor = Color.White, 
                FontWeight = FontWeight.Bold, 
                Margin = new Thickness(0, 0, 0, 10), 
                TextAlignment = TextAlignment.Center 
            });

            // Active Window Row
            var windowPanel = CreateRow("Active Window:", "INIT", Color.Silver, Color.Gray, out _windowValueTextBlock);
            mainPanel.AddChild(windowPanel);

            // Constraints
            mainPanel.AddChild(CreateRow("Max Risk Cap:", $"{MaxRisk:F1} R", Color.Silver, Color.Yellow, out _));
            mainPanel.AddChild(CreateRow("Trade Limit:", MaxTrades.ToString(), Color.Silver, Color.Yellow, out _));
            mainPanel.AddChild(CreateRow("Allowed Assets:", AllowedAssets, Color.Silver, Color.Yellow, out _));

            // Warning Banner
            _warningTextBlock = new TextBlock
            {
                Text = "INIT",
                ForegroundColor = Color.Gray,
                FontWeight = FontWeight.ExtraBold,
                Margin = new Thickness(0, 12, 0, 0),
                TextAlignment = TextAlignment.Center
            };
            mainPanel.AddChild(_warningTextBlock);

            // Mount to cTrader chart
            Chart.AddControl(dashboardBorder);
            
            // Force first visual update immediately
            UpdateDashboard();
        }

        private StackPanel CreateRow(string label, string value, Color labelColor, Color valueColor, out TextBlock valueBlock)
        {
            var panel = new StackPanel 
            { 
                Orientation = Orientation.Horizontal, 
                Margin = new Thickness(0, 3, 0, 3) 
            };
            
            panel.AddChild(new TextBlock { Text = label, ForegroundColor = labelColor, Width = 95 });
            
            valueBlock = new TextBlock 
            { 
                Text = value, 
                ForegroundColor = valueColor, 
                Width = 115, 
                TextAlignment = TextAlignment.Right 
            };
            
            panel.AddChild(valueBlock);
            return panel;
        }

        private void UpdateDashboard()
        {
            // Evaluate using the Broker's Server Time
            var now = Server.Time.TimeOfDay;
            
            bool inLondon = IsInSession(now, _londonStart, _londonEnd);
            bool inNY = IsInSession(now, _nyStart, _nyEnd);

            if (inLondon)
            {
                _windowValueTextBlock.Text = "LONDON";
                _windowValueTextBlock.ForegroundColor = Color.DeepSkyBlue;
                _warningTextBlock.Text = "STICK TO THE PLAN";
                _warningTextBlock.ForegroundColor = Color.LimeGreen;
            }
            else if (inNY)
            {
                _windowValueTextBlock.Text = "NEW YORK";
                _windowValueTextBlock.ForegroundColor = Color.DarkOrange;
                _warningTextBlock.Text = "STICK TO THE PLAN";
                _warningTextBlock.ForegroundColor = Color.LimeGreen;
            }
            else
            {
                _windowValueTextBlock.Text = "OUT OF SESSION";
                _windowValueTextBlock.ForegroundColor = Color.Red;
                _warningTextBlock.Text = "HANDS OFF KEYBOARD";
                _warningTextBlock.ForegroundColor = Color.Red;
            }
        }

        private bool IsInSession(TimeSpan now, TimeSpan start, TimeSpan end)
        {
            // Handles standard times as well as shifts that cross midnight
            if (start <= end)
            {
                return now >= start && now <= end;
            }
            else 
            {
                return now >= start || now <= end;
            }
        }
    }
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Session budgets for discretionary scalpers: beginner mistakes

Post by PTScalper »

Note on cTrader Time

Just like MT4/MT5, cTrader pulls Server.Time directly from the broker's environment. Adjust your input parameters strings (e.g., "08:00") based on your specific broker's timezone rather than your local Czech clock. Because it evaluates using native TimeSpan.TimeOfDay, it automatically handles rolling over past midnight seamlessly.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Post Reply