حل مشكلة تأخير فتح وإغلاق الصفقات وتحسين البوت ليعمل في الوقت الفعلي (On Tick) مع الموفينج المزدوج السريع DEMA.
OnBar() تعني أن البوت يفحص التقاطع فقط بمجرد انتهاء الشمعة وإغلاقها. هذا يتسبب دائماً في تأخير فتح الصفقة حتى الشمعة التالية.OnTick() ليعمل البوت في الوقت الفعلي مع كل تكة، مع إضافة مفتاح تحكم ExecuteOnBarClose لمن يفضل استقرار الإغلاق.التنفيذ الفوري مع كل تكة (On Tick) يضمن فتح الصفقة عند التقاطع بالضبط، ولكن في الأسواق المتذبذبة قد تتقاطع الخطوط وتتباعد عدة مرات خلال شمعة الـ 1 دقيقة قبل أن يستقر السعر. الكود الجديد المرفق يحتوي على ذكاء يمنع تكرار فتح صفقات شراء إضافية إذا كانت هناك صفقة شراء مفتوحة بالفعل.
C# هذا الكود تم حفظه وتحديثه تلقائياً في ملف البوت الخاص بك على جهازك في المسار الافتراضي لبرنامج cTrader. يمكنك إعادة بناء البوت (Build) مباشرة داخل المنصة.
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class SimpleCross_cBot : Robot
{
[Parameter("حجم اللوت (Volume in Lots)", DefaultValue = 0.01)]
public double Volume { 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; }
private DoubleExponentialMovingAverage _fastDema;
private DoubleExponentialMovingAverage _slowDema;
private SimpleMovingAverage _fastSma;
private SimpleMovingAverage _slowSma;
private bool? _lastFastAboveSlow;
public enum MAType
{
DEMA,
SMA
}
protected override void OnStart()
{
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()
{
// إذا تم تفعيل خيار التنفيذ عند الإغلاق فقط، نتجاهل التكات ونعتمد على 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)
{
ExecuteMarketOrder(tradeType, SymbolName, Symbol.QuantityToVolumeInUnits(Volume), "SimpleCross");
}
}
private void ClosePositions(TradeType tradeType)
{
foreach (var pos in Positions.Where(p => p.TradeType == tradeType && p.SymbolName == SymbolName))
{
ClosePosition(pos);
}
}
}
}
Pine Script v5 قمنا بتحويل المؤشر الخاص بك إلى استراتيجية (Strategy) متكاملة تقوم بمحاكاة الدخول والخرج وإغلاق الصفقات تلقائياً عند التقاطع. كما قمنا بإضافة دالة DEMA البرمجية.
//@version=5
strategy("Golden & Death Crossover DEMA Strategy", shorttitle="G/D DEMA Strategy", overlay=true, initial_capital=1000, default_qty_type=strategy.percent_of_equity, default_qty_value=10)
// المدخلات الأساسية
lengthFast = input.int(50, "فترة الموفينج السريع (Fast Period)", minval=1)
lengthSlow = input.int(200, "فترة الموفينج البطيء (Slow Period)", minval=1)
// دالة حساب المتوسط المزدوج DEMA يدوياً (لعدم توفره مدمجاً في Pine)
dema(src, length) =>
ema1 = ta.ema(src, length)
ema2 = ta.ema(ema1, length)
2 * ema1 - ema2
// حساب القيم
shortMA = dema(close, lengthFast)
longMA = dema(close, lengthSlow)
// حساب التقاطعات
goldenCross = ta.crossover(shortMA, longMA)
deathCross = ta.crossunder(shortMA, longMA)
// رسم الخطوط على الشارت
plot(shortMA, color=color.blue, title="Fast DEMA (50)", linewidth=2)
plot(longMA, color=color.red, title="Slow DEMA (200)", linewidth=2)
// منطق التداول الانعكاسي التلقائي
if (goldenCross)
strategy.close("Short")
strategy.entry("Long", strategy.long, comment="شراء - تقاطع ذهبي")
if (deathCross)
strategy.close("Long")
strategy.entry("Short", strategy.short, comment="بيع - تقاطع الموت")
// تلوين الخلفية بناءً على وضع الصفقة الحالي
inLong = strategy.position_size > 0
inShort = strategy.position_size < 0
bgcolor(inLong ? color.new(color.green, 93) : inShort ? color.new(color.red, 93) : na)