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);
}
}
}
}
}