[InputParameter("Volume Multiplier", 2)]
public double VolumeMultiplier { get; set; }
[InputParameter("Zone Validity Bars", 200)]
public int ZoneValidityBars { get; set; }
[InputParameter("Use Trend Filter", 1)]
public bool UseTrendFilter { get; set; }
[InputParameter("EMA Fast Période", 9)]
public int EmaFastPeriod { get; set; }
[InputParameter("EMA Slow Période", 21)]
public int EmaSlowPeriod { get; set; }
// --- Paramètres d'affichage ---
[InputParameter("Show Demand Zones", 1)]
public bool ShowDemandZones { get; set; }
[InputParameter("Show Supply Zones", 1)]
public bool ShowSupplyZones { get; set; }
[InputParameter("Demand Zone Color", (int)KnownColor.LimeGreen)]
public Color DemandColor { get; set; }
[InputParameter("Supply Zone Color", (int)KnownColor.OrangeRed)]
public Color SupplyColor { get; set; }
[InputParameter("Zone Opacity", 40)]
public int ZoneOpacity { get; set; }
[InputParameter("Show Zone Prices", 1)]
public bool ShowZonePrices { get; set; }
[InputParameter("Show Alerts", 1)]
public bool ShowAlerts { get; set; }
public object NotificationType { get; private set; }
// ========== VARIABLES GLOBALES ==========
private List<Zone> demandZones = new List<Zone>();
private List<Zone> supplyZones = new List<Zone>();
private Indicator emaFast;
private Indicator emaSlow;
private double avgVolume;
// Classe pour stocker les zones
private class Zone
{
public double High { get; set; }
public double Low { get; set; }
public int StartBar { get; set; }
public int EndBar { get; set; }
public bool IsActive { get; set; }
public Zone(double high, double low, int startBar, int endBar)
{
High = high;
Low = low;
StartBar = startBar;
EndBar = endBar;
IsActive = true;
}
}
// ========== INITIALISATION ==========
//public override void OnInitialize()
protected override void OnInit()
{
//emaFast = new EMA(EmaFastPeriod);
//emaSlow = new EMA(EmaSlowPeriod);
emaFast = Core.Instance.Indicators.BuiltIn.EMA(EmaFastPeriod, PriceType.Close);
this.AddIndicator(emaFast);
emaSlow = Core.Instance.Indicators.BuiltIn.EMA(EmaSlowPeriod, PriceType.Close);
this.AddIndicator(emaSlow);
demandZones.Clear();
supplyZones.Clear();
}
// ========== CALCULS ==========
public override void OnCalculate(int index, IBar bar)
{
// Calculer les EMA
emaFast.Calculate(index, bar.Close);
emaSlow.Calculate(index, bar.Close);
// Détecter les nouvelles zones
DetectDemandZone(index, bar);
DetectSupplyZone(index, bar);
// Vérifier la validité des zones existantes
CheckZoneValidity(index);
// Dessiner les zones sur la dernière barre
if (index == this.Count - 1)
{
DrawZones();
}
}
// ========== DÉTECTION DES ZONES DE DEMAND ==========
private void DetectDemandZone(int index, IBar bar)
{
if (index < 2) return;
// Condition : Mouvement baissier suivi d'un rebond fort avec volume
if (bar.Close > bar.Open && // Bougie haussière
this.GetBar(index - 1).Close < this.GetBar(index - 1).Open && // Bougie baissière précédente
bar.Close > this.GetBar(index - 1).Close && // Rebond
IsVolumeValid(index) &&
(IsUptrend(index) || !UseTrendFilter)) // Filtre de tendance
{
double zoneHigh = bar.High;
double zoneLow = this.GetBar(index - 1).Low;
// Éviter les doublons
foreach (var zone in demandZones)
{
if (Math.Abs(zone.High - zoneHigh) < 0.0001 * zoneHigh &&
Math.Abs(zone.Low - zoneLow) < 0.0001 * zoneLow)
{
return;
}
}
// Ajouter la nouvelle zone
demandZones.Add(new Zone(zoneHigh, zoneLow, index - 1, index));
if (ShowAlerts)
{
this.Notify(
$"NOUVELLE ZONE DE DEMAND détectée entre {zoneLow:0.00} et {zoneHigh:0.00}",
NotificationType.Alert);
//Alert($"NOUVELLE ZONE DE DEMAND détectée entre {zoneLow:0.00} et {zoneHigh:0.00}");
}
}
}
private void Notify(string v, object alert) => throw new NotImplementedException();
// ========== DÉTECTION DES ZONES DE SUPPLY ==========
private void DetectSupplyZone(int index, IBar bar)
{
if (index < 2) return;
// Condition : Mouvement haussier suivi d'un rejet fort avec volume
if (bar.Close < bar.Open && // Bougie baissière
this.GetBar(index - 1).Close > this.GetBar(index - 1).Open && // Bougie haussière précédente
bar.Close < this.GetBar(index - 1).Close && // Rejet
IsVolumeValid(index) &&
(IsDowntrend(index) || !UseTrendFilter)) // Filtre de tendance
{
double zoneHigh = this.GetBar(index - 1).High;
double zoneLow = bar.Low;
// Éviter les doublons
foreach (var zone in supplyZones)
{
if (Math.Abs(zone.High - zoneHigh) < 0.0001 * zoneHigh &&
Math.Abs(zone.Low - zoneLow) < 0.0001 * zoneLow)
{
return;
}
}
// Ajouter la nouvelle zone
supplyZones.Add(new Zone(zoneHigh, zoneLow, index - 1, index));
if (ShowAlerts)
{
Alerts($"NOUVELLE ZONE DE SUPPLY détectée entre {zoneLow:0.00} et {zoneHigh:0.00}");
}
}
}
private void Alerts(string v) => throw new NotImplementedException();
// ========== VÉRIFIER LA VALIDITÉ DES ZONES ==========
private void CheckZoneValidity(int index)
{
// Vérifier les zones de Demand
for (int i = 0; i < demandZones.Count; i++)
{
if (demandZones[i].IsActive && index - demandZones[i].EndBar > ZoneValidityBars)
{
demandZones[i].IsActive = false;
}
}
// Vérifier les zones de Supply
for (int i = 0; i < supplyZones.Count; i++)
{
if (supplyZones[i].IsActive && index - supplyZones[i].EndBar > ZoneValidityBars)
{
supplyZones[i].IsActive = false;
}
}
}
// ========== MÉTHODES AUXILIAIRES ==========
private bool IsUptrend(int index)
{
if (!UseTrendFilter || index < EmaSlowPeriod) return true;
return emaFast.Result[index] > emaSlow.Result[index];
}
private bool IsDowntrend(int index)
{
if (!UseTrendFilter || index < EmaSlowPeriod) return true;
return emaFast.Result[index] < emaSlow.Result[index];
}
private bool IsVolumeValid(int index)
{
avgVolume = CalculateAvgVolume(index);
return this.GetBar(index).Volume > VolumeMultiplier * avgVolume;
}
private double CalculateAvgVolume(int index)
{
double sum = 0;
int start = Math.Max(0, index - LookbackBars + 1);
for (int i = start; i <= index; i++)
{
sum += this.GetBar(i).Volume;
}
return sum / (index - start + 1);
}
// ========== DESSIN DES ZONES ==========
private void DrawZones()
{
// Dessiner les zones de Demand
if (ShowDemandZones)
{
foreach (var zone in demandZones)
{
if (zone.IsActive)
{
int x1 = this.Chart.BarToX(zone.StartBar);
int x2 = this.Chart.BarToX(zone.EndBar);
int y1 = this.Chart.PriceToY(zone.High);
int y2 = this.Chart.PriceToY(zone.Low);
// Créer une couleur transparente
Color transparentColor = Color.FromArgb(ZoneOpacity * 255 / 100, DemandColor);
// Dessiner le rectangle
this.Chart.DrawRectangle(
$"DemandZone_{zone.StartBar}_{zone.EndBar}",
x1, y2, x2 - x1, y1 - y2,
transparentColor, DemandColor, 1);
// Afficher les niveaux de prix
if (ShowZonePrices)
{
this.Chart.DrawText(
$"Demand: {zone.Low:0.00}-{zone.High:0.00}",
x2 + 5, (y1 + y2) / 2,
DemandColor, "Arial", 8);
}
}
}
}
// Dessiner les zones de Supply
if (ShowSupplyZones)
{
foreach (var zone in supplyZones)
{
if (zone.IsActive)
{
int x1 = this.Chart.BarToX(zone.StartBar);
int x2 = this.Chart.BarToX(zone.EndBar);
int y1 = this.Chart.PriceToY(zone.High);
int y2 = this.Chart.PriceToY(zone.Low);
// Créer une couleur transparente
Color transparentColor = Color.FromArgb(ZoneOpacity * 255 / 100, SupplyColor);
// Dessiner le rectangle
this.Chart.DrawRectangle(
$"SupplyZone_{zone.StartBar}_{zone.EndBar}",
x1, y1, x2 - x1, y2 - y1,
transparentColor, SupplyColor, 1);
// Afficher les niveaux de prix
if (ShowZonePrices)
{
this.Chart.DrawText(
$"Supply: {zone.Low:0.00}-{zone.High:0.00}",
x2 + 5, (y1 + y2) / 2,
SupplyColor, "Arial", 8);
}
}
}
}
}
}
Hi, i would like your help for compile my code please 👍
// =============================================
// INDICATEUR DEMAND & SUPPLY POUR QUANTOWER
// Optimisé pour le scalping sur NQ/ES (1min, 10min, 30min)
// Auteur : Adapté pour Boudigue
// =============================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using TradingPlatform.BusinessLayer;
namespace CustomIndicators
{
[DisplayName("Zones Demand & Supply (Scalping)")]
public class DemandSupplyZones : Indicator
{
// ========== PARAMÈTRES UTILISATEUR ==========
[InputParameter("Lookback Bars", 50)]
public int LookbackBars { get; set; }