Code: Select all
using System;
using System.Collections.Generic;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class XauInstitutionalEngine : Indicator
{
// ================= 1. Liquidity & Volatility =================
[Parameter("ATR Period", Group = "1. Volatility Baseline", DefaultValue = 14)]
public int AtrPeriod { get; set; }
[Parameter("Displacement Multiplier (x ATR)", Group = "1. Volatility Baseline", DefaultValue = 2.2)]
public double ImpulseMult { get; set; }
// ================= 2. Invalidation Matrix =================
[Parameter("Velocity Decay (Bars)", Group = "2. Invalidation Matrix", DefaultValue = 4)]
public int TimeStopBars { get; set; }
[Parameter("Expected R-Multiple", Group = "2. Invalidation Matrix", DefaultValue = 2.0)]
public double RrTarget { get; set; }
[Parameter("Max Spread (Pips)", Group = "2. Invalidation Matrix", DefaultValue = 3.5)]
public double MaxSpreadPips { get; set; }
// ================= 3. Prop Risk Sizing =================
[Parameter("Risk Per Setup (%)", Group = "3. Prop Risk", DefaultValue = 0.5)]
public double RiskPercent { get; set; }
// ================= Internal Architecture =================
private AverageTrueRange _atr;
private List<ActiveSetup> _activeSetups = new List<ActiveSetup>();
// UI Elements
private TextBlock _uiState;
private TextBlock _uiSpread;
private TextBlock _uiLotSize;
private TextBlock _uiTimeStop;
private Border _hudBorder;
private class ActiveSetup
{
public int StartIndex { get; set; }
public int Direction { get; set; }
public double EntryPrice { get; set; }
public double StopPrice { get; set; }
public double TargetPrice { get; set; }
public string Id { get; set; }
public double RequiredLots { get; set; }
}
protected override void Initialize()
{
_atr = Indicators.AverageTrueRange(AtrPeriod, MovingAverageType.Simple);
InitializeHUD();
}
// ================= BAR LEVEL: SETUP DETECTION =================
public override void Calculate(int index)
{
if (index < 25 || !IsLastBar) return;
// Purge expired setups via Time Stop
for (int i = _activeSetups.Count - 1; i >= 0; i--)
{
var setup = _activeSetups[i];
if (index - setup.StartIndex >= TimeStopBars)
{
Chart.DrawText(setup.Id + "_Msg", " VELOCITY DECAY (TIME STOP)", index, Bars.ClosePrices[index], Color.DimGray);
_activeSetups.RemoveAt(i);
}
}
double currentAtr = _atr.Result[index - 1]; // Use previous bar ATR for stability
double body = Math.Abs(Bars.ClosePrices[index] - Bars.OpenPrices[index]);
bool isBullImpulse = Bars.ClosePrices[index] > Bars.OpenPrices[index] && body > (currentAtr * ImpulseMult);
bool isBearImpulse = Bars.OpenPrices[index] > Bars.ClosePrices[index] && body > (currentAtr * ImpulseMult);
if (isBullImpulse || isBearImpulse)
{
int dir = isBullImpulse ? 1 : -1;
double entry = Bars.ClosePrices[index];
double stop = isBullImpulse ? Bars.LowPrices[index] : Bars.HighPrices[index];
// Add 1 micro-pip padding to stop to ensure it sits just beyond the wick
stop = dir == 1 ? stop - Symbol.TickSize : stop + Symbol.TickSize;
double riskDistance = Math.Abs(entry - stop);
double target = isBullImpulse ? (entry + riskDistance * RrTarget) : (entry - riskDistance * RrTarget);
// --- Institutional Risk Calculation ---
double riskAmount = Account.Equity * (RiskPercent / 100.0);
double pipDistance = riskDistance / Symbol.PipSize;
double exactVolume = (riskAmount / (pipDistance * Symbol.PipValue));
double normalizedLots = Symbol.NormalizeVolumeInUnits(exactVolume, RoundingMode.Down) / 100000.0; // Convert to standard lots
string setupId = "XAU_PI_" + index;
// Draw Visuals
Chart.DrawTrendLine(setupId + "_Stop", index, stop, index + TimeStopBars, stop, Color.Crimson, 2, LineStyle.Lines);
Chart.DrawTrendLine(setupId + "_Target", index, target, index + TimeStopBars, target, Color.Teal, 2, LineStyle.Lines);
Chart.DrawRectangle(setupId + "_RiskBox", index - 1, entry, index, stop, Color.FromArgb(40, dir == 1 ? Color.MediumSeaGreen : Color.Crimson));
_activeSetups.Add(new ActiveSetup
{
StartIndex = index, Direction = dir, EntryPrice = entry, StopPrice = stop, TargetPrice = target, Id = setupId, RequiredLots = normalizedLots
});
Notifications.PlaySound(SoundType.Doorbell);
}
}
// ================= TICK LEVEL: MICROSTRUCTURE EXECUTION =================
protected override void OnTick()
{
UpdateHUD();
if (_activeSetups.Count == 0) return;
// Tick-by-tick Invalidation Check (Zero Latency)
double ask = Symbol.Ask;
double bid = Symbol.Bid;
for (int i = _activeSetups.Count - 1; i >= 0; i--)
{
var setup = _activeSetups[i];
// Check Stop (Bid for Longs, Ask for Shorts)
bool hitStop = (setup.Direction == 1 && bid <= setup.StopPrice) ||
(setup.Direction == -1 && ask >= setup.StopPrice);
// Check Target
bool hitTarget = (setup.Direction == 1 && bid >= setup.TargetPrice) ||
(setup.Direction == -1 && ask <= setup.TargetPrice);
if (hitStop)
{
Chart.DrawText(setup.Id + "_Msg", " STRUCTURAL INVALIDATION", Bars.Count - 1, setup.StopPrice, Color.Crimson);
_activeSetups.RemoveAt(i);
}
else if (hitTarget)
{
Chart.DrawText(setup.Id + "_Msg", " TARGET REALIZED", Bars.Count - 1, setup.TargetPrice, Color.Teal);
_activeSetups.RemoveAt(i);
}
}
}
// ================= INSTITUTIONAL HUD (WPF) =================
private void InitializeHUD()
{
var grid = new Grid { Columns = 2, Rows = 4 };
grid.AddChild(new TextBlock { Text = "SYSTEM STATE:", Foreground = Color.Gray, Margin = 5 }, 0, 0);
_uiState = new TextBlock { Text = "SCANNING", Foreground = Color.White, Margin = 5, FontWeight = FontWeight.Bold };
grid.AddChild(_uiState, 0, 1);
grid.AddChild(new TextBlock { Text = "LIVE SPREAD:", Foreground = Color.Gray, Margin = 5 }, 1, 0);
_uiSpread = new TextBlock { Text = "0.0", Foreground = Color.White, Margin = 5, FontWeight = FontWeight.Bold };
grid.AddChild(_uiSpread, 1, 1);
grid.AddChild(new TextBlock { Text = "PROP LOT SIZING:", Foreground = Color.Gray, Margin = 5 }, 2, 0);
_uiLotSize = new TextBlock { Text = "-", Foreground = Color.White, Margin = 5, FontWeight = FontWeight.Bold };
grid.AddChild(_uiLotSize, 2, 1);
grid.AddChild(new TextBlock { Text = "T-MINUS (TIME STOP):", Foreground = Color.Gray, Margin = 5 }, 3, 0);
_uiTimeStop = new TextBlock { Text = "-", Foreground = Color.White, Margin = 5, FontWeight = FontWeight.Bold };
grid.AddChild(_uiTimeStop, 3, 1);
_hudBorder = new Border
{
BackgroundColor = Color.FromArgb(220, 15, 15, 15),
BorderColor = Color.FromArgb(100, 100, 100, 100),
BorderThickness = 1,
CornerRadius = 3,
Margin = 10,
HorizontalAlignment = HorizontalAlignment.Right,
VerticalAlignment = VerticalAlignment.Top,
Child = grid
};
Chart.AddControl(_hudBorder);
}
private void UpdateHUD()
{
double currentSpread = Math.Round(Symbol.Spread / Symbol.PipSize, 1);
_uiSpread.Text = $"{currentSpread} Pips";
_uiSpread.Foreground = currentSpread > MaxSpreadPips ? Color.Crimson : Color.Teal;
if (_activeSetups.Any())
{
var active = _activeSetups.Last(); // Track most recent
int barsElapsed = Bars.Count - 1 - active.StartIndex;
_uiState.Text = "IN TRADE (VULNERABLE)";
_uiState.Foreground = Color.Gold;
_uiLotSize.Text = $"{Math.Round(active.RequiredLots, 2)} Lots (Risking {RiskPercent}%)";
_uiLotSize.Foreground = Color.Cyan;
_uiTimeStop.Text = $"{TimeStopBars - barsElapsed} Bars Remaining";
_uiTimeStop.Foreground = Color.White;
}
else
{
_uiState.Text = "SCANNING LIQUIDITY";
_uiState.Foreground = Color.DarkGray;
_uiLotSize.Text = "-";
_uiTimeStop.Text = "-";
}
}
protected override void OnDeinitialize()
{
if (_hudBorder != null) Chart.RemoveControl(_hudBorder);
}
}
}