Page 2 of 2
Re: Christmas week session map: when I simply do not trade
Posted: Mon Sep 28, 2026 9:55 pm
by PTScalper
Why this C# Implementation Shines
Responsive UI: Because it uses StackPanel and Border controls natively, the UI card scales perfectly and centers itself automatically. You don't have to fiddle with X and Y pixel coordinates if you resize the cTrader window.
Flawless Pip Calculation: Calculating pips in MT4/MT5 requires checking if the broker is 3-digit, 4-digit, or 5-digit. In cTrader, Symbol.PipSize is universally reliable regardless of whether you are looking at EURUSD, Gold (XAUUSD), or an Equity index.
Server Time Safety: The indicator specifically calls Server.Time instead of DateTime.Now. This ensures the script evaluates the true broker time (bypassing any timezone offsets or local PC clock issues) to determine if it is officially "the holiday window" in the market.
Re: Christmas week session map: when I simply do not trade
Posted: Mon Sep 28, 2026 9:56 pm
by PTScalper
Here is a production-grade implementation for cTrader.
This version is refactored to align with enterprise C# standards, separating state evaluation from UI rendering, optimizing the tick-level processing, and upgrading the visuals to a modern, dark-mode terminal aesthetic.
It is also structured so the core logic can be cleanly extracted into a cBot if you decide to fully automate the execution lock-out in the future.
Re: Christmas week session map: when I simply do not trade
Posted: Mon Sep 28, 2026 9:56 pm
by PTScalper
MarketConditionMonitor.cs
Code: Select all
using System;
using cAlgo.API;
using cAlgo.API.Internals;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class MarketConditionMonitor : Indicator
{
#region Parameters
[Parameter("Start Month", DefaultValue = 12, Group = "Holiday Lockdown", MinValue = 1, MaxValue = 12)]
public int StartMonth { get; set; }
[Parameter("Start Day", DefaultValue = 20, Group = "Holiday Lockdown", MinValue = 1, MaxValue = 31)]
public int StartDay { get; set; }
[Parameter("End Month", DefaultValue = 1, Group = "Holiday Lockdown", MinValue = 1, MaxValue = 12)]
public int EndMonth { get; set; }
[Parameter("End Day", DefaultValue = 3, Group = "Holiday Lockdown", MinValue = 1, MaxValue = 31)]
public int EndDay { get; set; }
[Parameter("Max Spread (Pips)", DefaultValue = 2.5, Group = "Liquidity Monitoring", MinValue = 0.1)]
public double MaxSpreadPips { get; set; }
#endregion
#region Constants & Fields
// Professional Dark Theme Palette
private const string ColorBackground = "#E6111111"; // 90% Opacity Dark Charcoal
private const string ColorBorderHoliday = "#FFD32F2F"; // Material Red 700
private const string ColorBorderSpread = "#FFFBC02D"; // Material Yellow 700
private const string ColorTextPrimary = "#FFFFFFFF";
private const string ColorTextSecondary = "#FFB0B0B0";
private const string ColorSpreadSafe = "#FF81C784"; // Material Green 300
private const string ColorSpreadDanger = "#FFE57373"; // Material Red 300
private Border _mainContainer;
private TextBlock _lblHeader;
private TextBlock _lblSubtext;
private TextBlock _lblSpreadData;
private MarketState _currentState = MarketState.Normal;
// Cache to prevent redundant UI thread updates
private double _lastRenderedSpread = -1;
private MarketState _lastRenderedState = MarketState.Normal;
private enum MarketState
{
Normal,
SpreadBlown,
HolidayLockdown
}
#endregion
#region Initialization
protected override void Initialize()
{
ConstructUI();
EvaluateMarketConditions();
}
private void ConstructUI()
{
_lblHeader = new TextBlock
{
TextAlignment = TextAlignment.Center,
FontWeight = FontWeight.ExtraBold,
FontSize = 14,
ForegroundColor = Color.FromHex(ColorTextPrimary),
Margin = new Thickness(0, 0, 0, 4)
};
_lblSubtext = new TextBlock
{
TextAlignment = TextAlignment.Center,
FontWeight = FontWeight.Normal,
FontSize = 11,
ForegroundColor = Color.FromHex(ColorTextSecondary),
Margin = new Thickness(0, 0, 0, 10)
};
_lblSpreadData = new TextBlock
{
TextAlignment = TextAlignment.Center,
FontWeight = FontWeight.Bold,
FontSize = 12
};
var layoutGrid = new StackPanel
{
Orientation = Orientation.Vertical,
HorizontalAlignment = HorizontalAlignment.Center,
Margin = new Thickness(20, 15, 20, 15)
};
layoutGrid.AddChild(_lblHeader);
layoutGrid.AddChild(_lblSubtext);
layoutGrid.AddChild(_lblSpreadData);
_mainContainer = new Border
{
Child = layoutGrid,
BackgroundColor = Color.FromHex(ColorBackground),
BorderThickness = new Thickness(0, 3, 0, 0), // Top-heavy border for sleek tech look
CornerRadius = 3,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Top,
Margin = new Thickness(0, 60, 0, 0),
IsVisible = false
};
Chart.AddControl(_mainContainer);
}
#endregion
#region Core Logic
public override void Calculate(int index)
{
// Abort processing for historical bars to preserve CPU cycles
if (!IsLastIndex) return;
EvaluateMarketConditions();
}
private void EvaluateMarketConditions()
{
double currentSpread = Math.Round((Symbol.Ask - Symbol.Bid) / Symbol.PipSize, 1);
bool isHoliday = IsWithinHolidayWindow(Server.Time);
bool isSpreadBlown = currentSpread >= MaxSpreadPips;
MarketState newState = MarketState.Normal;
// Hierarchy of states: Holiday lockdown supersedes a blown spread
if (isHoliday)
newState = MarketState.HolidayLockdown;
else if (isSpreadBlown)
newState = MarketState.SpreadBlown;
// Update UI only on state change or significant spread change to prevent layout thrashing
if (newState != _lastRenderedState || Math.Abs(currentSpread - _lastRenderedSpread) >= 0.1)
{
UpdateInterface(newState, currentSpread);
_lastRenderedState = newState;
_lastRenderedSpread = currentSpread;
}
}
private bool IsWithinHolidayWindow(DateTime currentTime)
{
bool isPastStart = (currentTime.Month > StartMonth) || (currentTime.Month == StartMonth && currentTime.Day >= StartDay);
bool isBeforeEnd = (currentTime.Month < EndMonth) || (currentTime.Month == EndMonth && currentTime.Day <= EndDay);
return StartMonth > EndMonth
? (isPastStart || isBeforeEnd)
: (isPastStart && isBeforeEnd);
}
#endregion
#region UI Rendering
private void UpdateInterface(MarketState state, double currentSpread)
{
if (state == MarketState.Normal)
{
_mainContainer.IsVisible = false;
return;
}
_mainContainer.IsVisible = true;
_lblSpreadData.Text = $"LIVE SPREAD: {currentSpread:F1} PIPS | MAX: {MaxSpreadPips:F1} PIPS";
_lblSpreadData.ForegroundColor = currentSpread >= MaxSpreadPips
? Color.FromHex(ColorSpreadDanger)
: Color.FromHex(ColorSpreadSafe);
switch (state)
{
case MarketState.HolidayLockdown:
_mainContainer.BorderColor = Color.FromHex(ColorBorderHoliday);
_lblHeader.Text = "SYSTEM LOCKED: HOLIDAY CONDITIONS";
_lblSubtext.Text = "MARKET MICROSTRUCTURE COMPROMISED • JOURNAL ONLY";
break;
case MarketState.SpreadBlown:
_mainContainer.BorderColor = Color.FromHex(ColorBorderSpread);
_lblHeader.Text = "WARNING: LIQUIDITY VACUUM DETECTED";
_lblSubtext.Text = "SPREAD EXCEEDS ACCEPTABLE EXECUTION THRESHOLD";
break;
}
}
#endregion
}
}
Re: Christmas week session map: when I simply do not trade
Posted: Mon Sep 28, 2026 9:56 pm
by PTScalper
Architectural Upgrades
State Machine Hierarchy: The indicator now evaluates states hierarchically (MarketState.Normal, SpreadBlown, HolidayLockdown). Holiday rules override everything else.
UI Thread Optimization: The EvaluateMarketConditions method caches the previous tick's state and spread. It only forces a UI repaint if the state changes or the spread moves by a full 0.1 pip increment, eliminating unnecessary layout thrashing.
Encapsulation: The UI construction, layout rendering, and mathematical evaluation are cleanly isolated into distinct regions.
Modern Aesthetics: Uses a top-heavy accent border (like modern trading terminals) against a 90% opacity charcoal background. The color palette relies on subdued Material Design hex codes rather than aggressive base colors, keeping it visible but clean.