using System; using System.Linq; using System.Net; using System.Text; using cAlgo.API; using cAlgo.API.Indicators; using cAlgo.API.Internals; using cAlgo.Indicators; namespace cAlgo.Robots { [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)] public class SimpleCross_cBot : Robot { [Parameter("حجم اللوت (Volume in Lots)", DefaultValue = 0.01, Group = "Money Management")] public double Volume { get; set; } [Parameter("استخدام إدارة المخاطر (Use Risk %)", DefaultValue = false, Group = "Money Management")] public bool UseRiskManagement { get; set; } [Parameter("نسبة المخاطرة % (Risk %)", DefaultValue = 1.0, Group = "Money Management")] public double RiskPercentage { get; set; } [Parameter("وقف الخسارة بالنقاط (Stop Loss Pips) 0=إلغاء", DefaultValue = 0, Group = "Protection")] public int StopLoss { get; set; } [Parameter("جني الأرباح بالنقاط (Take Profit Pips) 0=إلغاء", DefaultValue = 0, Group = "Protection")] public int TakeProfit { get; set; } [Parameter("تفعيل الوقف المتحرك (Enable Trailing Stop)", DefaultValue = false, Group = "Protection")] public bool EnableTrailingStop { get; set; } [Parameter("بدء الوقف المتحرك بعد (Trailing Trigger Pips)", DefaultValue = 20, Group = "Protection")] public int TrailingTrigger { get; set; } [Parameter("مسافة الوقف المتحرك (Trailing Step Pips)", DefaultValue = 10, Group = "Protection")] public int TrailingStep { get; set; } [Parameter("تفعيل فلتر وقت التداول (Enable Time Filter)", DefaultValue = false, Group = "Time Management")] public bool EnableTimeFilter { get; set; } [Parameter("وقت بدء التداول (Start Time hh:mm)", DefaultValue = "08:00", Group = "Time Management")] public string StartTimeStr { get; set; } [Parameter("وقت إنهاء التداول (End Time hh:mm)", DefaultValue = "18:00", Group = "Time Management")] public string EndTimeStr { get; set; } [Parameter("إغلاق الصفقات بانتهاء الوقت (Close Outside Hours)", DefaultValue = false, Group = "Time Management")] public bool CloseOutsideHours { get; set; } [Parameter("المتوسط السريع (Fast Period)", DefaultValue = 50)] public int FastPeriods { get; set; } [Parameter("المتوسط البطيء (Slow Period)", DefaultValue = 200)] public int SlowPeriods { get; set; } [Parameter("نوع المتوسط (MA Type)", DefaultValue = MAType.DEMA)] public MAType SelectedMAType { get; set; } [Parameter("التنفيذ عند الإغلاق فقط (On Bar Close Only)", DefaultValue = false)] public bool ExecuteOnBarClose { get; set; } [Parameter("تفعيل التليجرام (Enable Telegram)", DefaultValue = false, Group = "Telegram")] public bool EnableTelegram { get; set; } [Parameter("توكن البوت (Bot Token)", DefaultValue = "8836868237:AAHfc6NaWUfXgr0KJPTWtDT1tSpASwXNwus", Group = "Telegram")] public string TelegramBotToken { get; set; } [Parameter("معرف القناة (Channel ID)", DefaultValue = "-1004490418053", Group = "Telegram")] public string TelegramChatId { get; set; } private DoubleExponentialMovingAverage _fastDema; private DoubleExponentialMovingAverage _slowDema; private SimpleMovingAverage _fastSma; private SimpleMovingAverage _slowSma; private bool? _lastFastAboveSlow; public enum MAType { DEMA, SMA } private TimeSpan _startTime; private TimeSpan _endTime; protected override void OnStart() { if (EnableTimeFilter) { TimeSpan.TryParse(StartTimeStr, out _startTime); TimeSpan.TryParse(EndTimeStr, out _endTime); } if (SelectedMAType == MAType.DEMA) { _fastDema = Indicators.DoubleExponentialMovingAverage(Bars.ClosePrices, FastPeriods); _slowDema = Indicators.DoubleExponentialMovingAverage(Bars.ClosePrices, SlowPeriods); } else { _fastSma = Indicators.SimpleMovingAverage(Bars.ClosePrices, FastPeriods); _slowSma = Indicators.SimpleMovingAverage(Bars.ClosePrices, SlowPeriods); } } protected override void OnTick() { // إدارة أوقات التداول (الإغلاق الإجباري خارج الأوقات) if (EnableTimeFilter && CloseOutsideHours && !IsWithinTradingHours()) { CloseAllPositions(); } // إدارة الوقف المتحرك في كل تكة إذا كان مفعلاً if (EnableTrailingStop) { ManageTrailingStop(); } // إذا تم تفعيل خيار التنفيذ عند الإغلاق فقط، نتجاهل التكات ونعتمد على OnBar if (ExecuteOnBarClose) return; double fastCurrent = (SelectedMAType == MAType.DEMA) ? _fastDema.Result.Last(0) : _fastSma.Result.Last(0); double slowCurrent = (SelectedMAType == MAType.DEMA) ? _slowDema.Result.Last(0) : _slowSma.Result.Last(0); // تهيئة الحالة السابقة عند أول تكة باستخدام الشمعة المغلقة السابقة if (!_lastFastAboveSlow.HasValue) { double fastPrevious = (SelectedMAType == MAType.DEMA) ? _fastDema.Result.Last(1) : _fastSma.Result.Last(1); double slowPrevious = (SelectedMAType == MAType.DEMA) ? _slowDema.Result.Last(1) : _slowSma.Result.Last(1); _lastFastAboveSlow = fastPrevious > slowPrevious; } bool isFastAboveSlow = fastCurrent > slowCurrent; if (isFastAboveSlow && !_lastFastAboveSlow.Value) { ExecuteTrade(TradeType.Buy); } else if (!isFastAboveSlow && _lastFastAboveSlow.Value) { ExecuteTrade(TradeType.Sell); } _lastFastAboveSlow = isFastAboveSlow; } protected override void OnBar() { // إذا تم تفعيل خيار التنفيذ عند الإغلاق، نقوم بالفحص عند اكتمال الشمعة السابقة if (!ExecuteOnBarClose) return; double fastCurrent = (SelectedMAType == MAType.DEMA) ? _fastDema.Result.Last(1) : _fastSma.Result.Last(1); double fastPrevious = (SelectedMAType == MAType.DEMA) ? _fastDema.Result.Last(2) : _fastSma.Result.Last(2); double slowCurrent = (SelectedMAType == MAType.DEMA) ? _slowDema.Result.Last(1) : _slowSma.Result.Last(1); double slowPrevious = (SelectedMAType == MAType.DEMA) ? _slowDema.Result.Last(2) : _slowSma.Result.Last(2); bool goldenCross = (fastCurrent > slowCurrent && fastPrevious <= slowPrevious); bool deathCross = (fastCurrent < slowCurrent && fastPrevious >= slowPrevious); if (goldenCross) { ExecuteTrade(TradeType.Buy); } else if (deathCross) { ExecuteTrade(TradeType.Sell); } } private void ExecuteTrade(TradeType tradeType) { // 1. إغلاق جميع صفقات الاتجاه المعاكس المفتوحة TradeType oppositeType = (tradeType == TradeType.Buy) ? TradeType.Sell : TradeType.Buy; ClosePositions(oppositeType); // 2. فتح الصفقة الجديدة بالاتجاه الصحيح في التقاطع فوراً if (Positions.Count(p => p.TradeType == tradeType && p.SymbolName == SymbolName) == 0) { // منع فتح صفقات جديدة خارج أوقات التداول if (EnableTimeFilter && !IsWithinTradingHours()) { return; } double calculatedVolume = CalculateVolume(); double? sl = StopLoss > 0 ? (double?)StopLoss : null; double? tp = TakeProfit > 0 ? (double?)TakeProfit : null; var result = ExecuteMarketOrder(tradeType, SymbolName, calculatedVolume, "SimpleCross", sl, tp); if (result.IsSuccessful) { string emoji = tradeType == TradeType.Buy ? "🟢" : "🔴"; string msg = $"{emoji} إشارة جديدة: {tradeType}\n" + $"الزوج: {SymbolName}\n" + $"سعر الدخول: {result.Position.EntryPrice}\n" + $"اللوت: {calculatedVolume}"; SendTelegramMessage(msg); } } } private void ClosePositions(TradeType tradeType) { foreach (var pos in Positions.Where(p => p.TradeType == tradeType && p.SymbolName == SymbolName)) { double currentProfit = pos.GrossProfit; var result = ClosePosition(pos); if (result.IsSuccessful) { string profitEmoji = currentProfit > 0 ? "✅" : "❌"; string msg = $"{profitEmoji} إغلاق صفقة: {pos.TradeType}\n" + $"الزوج: {pos.SymbolName}\n" + $"الربح التقريبي: {currentProfit:F2}"; SendTelegramMessage(msg); } } } private void SendTelegramMessage(string message) { if (!EnableTelegram || string.IsNullOrEmpty(TelegramBotToken) || string.IsNullOrEmpty(TelegramChatId)) return; try { ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; string url = $"https://api.telegram.org/bot{TelegramBotToken}/sendMessage"; // تجهيز الرسالة لتكون بصيغة JSON متوافقة string payload = $"{{\"chat_id\": \"{TelegramChatId}\", \"text\": \"{message}\", \"parse_mode\": \"HTML\"}}"; using (var webClient = new WebClient()) { webClient.Headers[HttpRequestHeader.ContentType] = "application/json"; webClient.Encoding = Encoding.UTF8; webClient.UploadString(url, "POST", payload); } } catch (Exception ex) { Print("خطأ في إرسال رسالة التليجرام: " + ex.Message); } } private double CalculateVolume() { if (!UseRiskManagement || StopLoss <= 0) { return Symbol.QuantityToVolumeInUnits(Volume); } // حساب اللوت بناءً على نسبة المخاطرة والستوب لوز double riskAmount = Account.Balance * (RiskPercentage / 100.0); double valuePerPip = Symbol.PipValue; if (valuePerPip == 0) return Symbol.QuantityToVolumeInUnits(Volume); double exactVolume = riskAmount / (StopLoss * valuePerPip); double normalizedVolume = Symbol.NormalizeVolumeInUnits(exactVolume, RoundingMode.Down); if (normalizedVolume < Symbol.VolumeInUnitsMin) return Symbol.VolumeInUnitsMin; if (normalizedVolume > Symbol.VolumeInUnitsMax) return Symbol.VolumeInUnitsMax; return normalizedVolume; } private void ManageTrailingStop() { foreach (var position in Positions.Where(p => p.SymbolName == SymbolName && p.Label == "SimpleCross")) { if (position.TradeType == TradeType.Buy) { double distance = Symbol.Bid - position.EntryPrice; if (distance >= TrailingTrigger * Symbol.PipSize) { double newStopLoss = Math.Round(Symbol.Bid - (TrailingStep * Symbol.PipSize), Symbol.Digits); if (position.StopLoss == null || newStopLoss > Math.Round(position.StopLoss.Value, Symbol.Digits)) { ModifyPosition(position, newStopLoss, position.TakeProfit); } } } else if (position.TradeType == TradeType.Sell) { double distance = position.EntryPrice - Symbol.Ask; if (distance >= TrailingTrigger * Symbol.PipSize) { double newStopLoss = Math.Round(Symbol.Ask + (TrailingStep * Symbol.PipSize), Symbol.Digits); if (position.StopLoss == null || newStopLoss < Math.Round(position.StopLoss.Value, Symbol.Digits)) { ModifyPosition(position, newStopLoss, position.TakeProfit); } } } } } private bool IsWithinTradingHours() { var now = Server.Time.TimeOfDay; if (_startTime < _endTime) { return now >= _startTime && now <= _endTime; } else { // إذا كان الوقت يمتد لليوم التالي (مثلا من 20:00 إلى 04:00) return now >= _startTime || now <= _endTime; } } private void CloseAllPositions() { var positionsToClose = Positions.Where(p => p.SymbolName == SymbolName && p.Label == "SimpleCross").ToArray(); foreach (var pos in positionsToClose) { double currentProfit = pos.GrossProfit; var result = ClosePosition(pos); if (result.IsSuccessful) { string profitEmoji = currentProfit > 0 ? "✅" : "❌"; string msg = $"{profitEmoji} إغلاق بسبب انتهاء وقت التداول: {pos.TradeType}\n" + $"الزوج: {pos.SymbolName}\n" + $"الربح التقريبي: {currentProfit:F2}"; SendTelegramMessage(msg); } } } } }