انتقل إلى المحتوى

كائنات الرسم البياني والرسومات

تسمح كائنات الرسم البياني (الرسومات) برسم الخطوط أو الأشكال الهندسية على الرسوم البيانية لـ cTrader. باستخدامها، يمكنك رسم الأنماط أو إظهار أحداث معينة على الرسوم البيانية بناءً على بيانات cBot أو المؤشر الخاص بك.

تستخدم كائنات الرسم البياني إحداثيات X و Y لتحديد المواقع.

  • يمثل المحور X وقت الرسم البياني أو فهارس الشريط.
  • المحور Y هو سعر الرمز.

جميع كائنات الرسم البياني مشتقة من الفئة الأساسية ChartObject، مما يعني أن جميعها ترث ميزات أساسية معينة.

عينات كود كائنات الرسم البياني

الرسم داخل نوافذ المؤشر

عند إنشاء كائنات الرسم البياني، لست مقيدًا بالرسم البياني الرئيسي للرمز. في الواقع، يمكنك رسم كائنات الرسم البياني داخل أي نوافذ تحتوي على مخرجات المؤشر.

تحتوي فئة Chart على مجموعة IndicatorAreas. وهي تحتوي على جميع النوافذ غير المتراكبة أو المنفصلة التي يمكن للمؤشرات عرض مخرجاتها فيها.

يمكنك أيضًا الوصول إلى منطقة المؤشر الحالية الخاصة بك باستخدام خاصية IndicatorArea لفئة Indicator الخاصة بك.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = false, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var verticalLine = IndicatorArea.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);
        }

        public override void Calculate(int index)
        {
        }
    }
}

عند تشغيل مثيل للمؤشر أعلاه، يجب أن ترى خطًا أحمر في نافذة مؤشر منفصلة. عند إنشاء رسوم بيانية في مناطق مؤشر منفصلة، يمكنك استخدام جميع طرق الرسم حيث أن كلاً من Chart و IndicatorArea يرثان من الفئة الأساسية ChartArea.

النص الثابت

بدلاً من استخدام إحداثيات X و Y لتحديد المواقع، يستخدم النص الثابت محاذاة أفقية وعمودية ثابتة. لإظهار أو رسم نص ثابت، استخدم طريقة DrawStaticText().

1
var staticText = Chart.DrawStaticText("static", "This is the text that will be shown", VerticalAlignment.Center, HorizontalAlignment.Center, Color.Red);

إذا قمت بإرفاق كائن الرسم البياني هذا بمؤشر وتشغيل مثيل، فسترى النص التالي في الرسم البياني الرئيسي.

Image title

الخط العمودي

استخدم طريقة DrawVerticalLine() لرسم خط عمودي.

1
2
3
var verticalLine = Chart.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);
// Or
var verticalLine = Chart.DrawVerticalLine("line", Bars.OpenTimes[Chart.LastVisibleBarIndex], Color.Red);

الخط الأفقي

استخدم طريقة DrawHorizontalLine() لرسم خط أفقي.

1
2
3
/* We use the maximum of the high prices
of the last ten bars as the Y coordinate. */ 
var horizontalLine = Chart.DrawHorizontalLine("line", Bars.HighPrices.Maximum(10), Color.Red);

خط الاتجاه

يبدأ خط الاتجاه من نقطة معينة في الرسم البياني وينتهي عند نقطة أخرى. خطوط الاتجاه مفيدة لإنشاء أشكال مختلفة أو أنماط معقدة.

لرسم خط اتجاه استخدم طريقة DrawTrendLine().

1
2
3
4
5
6
7
/* We draw a line from the low price
 of the first visible bar to the high price
 of the last visible bar on the chart. */
var trendLine = Chart.DrawTrendLine("line", Chart.FirstVisibleBarIndex, Bars.LowPrices[Chart.FirstVisibleBarIndex], Chart.LastVisibleBarIndex, Bars.HighPrices[Chart.LastVisibleBarIndex], Color.Red);

// Alternatively, consider the following.
var trendLine = Chart.DrawTrendLine("line", Bars.OpenTimes[Chart.FirstVisibleBarIndex], Bars.LowPrices[Chart.FirstVisibleBarIndex], Bars.OpenTimes[Chart.LastVisibleBarIndex], Bars.HighPrices[Chart.LastVisibleBarIndex], Color.Red);

المستطيل

استخدم طريقة DrawRectangle() لرسم مستطيل.

1
2
3
4
5
6
7
var rectangle = Chart.DrawRectangle("rectangle", Chart.FirstVisibleBarIndex + 1, Bars.LowPrices[Chart.FirstVisibleBarIndex + 1], Chart.LastVisibleBarIndex, Bars.HighPrices[Chart.LastVisibleBarIndex], Color.Red);

/* We fill the rectangle with a transparent color.
By using its current color, we only change the alpha
channel. */
rectangle.IsFilled = true;
rectangle.Color = Color.FromArgb(80, rectangle.Color);

المثلث

استخدم طريقة DrawTriangle() لرسم مثلث.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var middleX = Chart.FirstVisibleBarIndex + (Chart.LastVisibleBarIndex - Chart.FirstVisibleBarIndex) / 2;
var middleY = Bars.LowPrices[Chart.FirstVisibleBarIndex] + (Bars.HighPrices[Chart.LastVisibleBarIndex] - Bars.LowPrices[Chart.FirstVisibleBarIndex]) / 2;

var triangle = Chart.DrawTriangle("triangle", Chart.FirstVisibleBarIndex, Bars.LowPrices[Chart.FirstVisibleBarIndex], middleX, middleY, Chart.LastVisibleBarIndex, Bars.LowPrices[Chart.FirstVisibleBarIndex], Color.Red);

// We fill the triangle with a transparent color
// by using it's current color, we change only the alpha channel

/* We fill the triangle with a transparent color.
By using its current color, we only change the alpha
channel. */
triangle.IsFilled = true;
triangle.Color = Color.FromArgb(80, triangle.Color);

كائنات الرسم البياني الأخرى

من أجل الإيجاز، لم نذكر العديد من كائنات الرسم البياني الأخرى في مقتطفات الكود أعلاه. تشمل هذه الكائنات على سبيل المثال لا الحصر ما يلي:

  • بيضاوي
  • الأيقونة
  • شوكة أندروز
  • القناة متساوية الأبعاد
  • امتداد فيبوناتشي
  • مروحة فيبوناتشي
  • تصحيح فيبوناتشي

يمكن رسم جميع هذه الكائنات باستخدام طرق Draw...() ذات أسماء مماثلة تقبل معلمات مماثلة.

العائد على المخاطرة

توفر واجهة ChartRiskReward أنواعًا تمكنك من إنشاء وإدارة كائنات العائد على المخاطرة برمجيًا على الرسوم البيانية.

يوضح الكود أدناه كيفية إنشاء مؤشر يرسم كائن العائد على المخاطرة:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
using System;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo
{
    [Indicator(AccessRights = AccessRights.None, IsOverlay = true)]
    public class SimpleRiskReward : Indicator
    {
        protected override void Initialize()
        {
            var type = new ChartRiskRewardFixedRiskType(
                ChartRiskRewardAmountType.BalancePercentage, 
                1                                            
            );
            var tradeType = TradeType.Buy;
            var orderType = OrderType.Market;

            var entryPrice = Chart.Bars.LastBar.Close;
            var time1 = Chart.LastVisibleBarIndex - 20; 
            var time2 = Chart.LastVisibleBarIndex;      

            var rr = Chart.DrawRiskReward(
                "SimpleRR",     
                time1,           
                time2,            
                entryPrice,       
                orderType,        
                tradeType,        
                type              
            );

            rr.IsInteractive = true;

            rr.RiskColor = Color.Yellow;
            rr.RiskLineStyle = LineStyle.DotsRare;
            rr.RiskThickness = 3;

            rr.RewardColor = Color.Blue;
            rr.RewardLineStyle = LineStyle.LinesDots;
            rr.RewardThickness = 2;

            PrintRRInfo(rr);
        }

        private void PrintRRInfo(ChartRiskReward rr)
        {
            Print($"Name: {rr.Name} | Type: {rr.Type.GetType().Name} | Order Type: {rr.OrderType} | Trade Type: {rr.TradeType} | Time 1: {rr.Time1:o} | Time 2: {rr.Time2:o} | Entry: {rr.EntryPrice} | SL: {rr.StopLossPrice} | TP: {rr.TakeProfitPrice} | RR: {rr.RiskRewardRatio} | Volume: {rr.VolumeInUnits}");
        }

        public override void Calculate(int index)
        {
        }
    }
}

إعدادات الكائن الرئيسية

تسمية كائنات الرسم البياني

كلما حاولت رسم كائن رسم بياني، يجب عليك توفير اسمه كوسيطة لطريقة الرسم.

يجب أن تكون جميع أسماء كائنات الرسم البياني فريدة. إذا لم يتم استيفاء هذا المتطلب، فأنت تخاطر بتجاوز كائنات الرسم البياني لكائنات الرسم البياني ذات الأسماء نفسها اعتمادًا على أوقات تنفيذها. يمكنك استخدام قيمة فهرس الشريط الحالي أو الوقت الحالي لإنشاء أسماء فريدة لكل كائن.

الوصول إلى كائنات الرسم البياني

تحتوي مجموعة Objects على جميع كائنات الرسم البياني. تتضمن هذه المجموعة الكائنات المرسومة من قبل المستخدم. نتيجة لذلك، يمكن الوصول إلى مجموعة Objects لإزالة الكائنات من الرسوم البيانية أو تعديل خصائصها.

يوضح المثال أدناه كيفية الوصول إلى أعضاء مجموعة Objects:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
using cAlgo.API;
using System.Linq;
namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            foreach (var chartObject in Chart.Objects)
            {
                /* If the object is a trend line 
                we change its Y1/2 properties */
                if (chartObject is ChartTrendLine trendLine)
                {
                    trendLine.Y1 = Chart.BottomY;
                    trendLine.Y2 = Chart.TopY;
                }
            }

            /* Here, we filter all objects of the 'ChartRectangle'
            type. */
            var rectangles = from chartObject in Chart.Objects
                             where chartObject is ChartRectangle
                             select chartObject as ChartRectangle;

            /* We select only the chart objects with a name that
            begins with "MyObjects". */
            var myObjects = from chartObject in Chart.Objects
                            where chartObject.Name.StartsWith("MyObjects", System.StringComparison.OrdinalIgnoreCase)
                            select chartObject;

            /* We select only interactive objects. If an object
            is interactive, it will not be removed when the 
            indicator is removed or reloaded. */
            var interactiveObjects = from chartObject in Chart.Objects
                                     where chartObject.IsInteractive
                                     select chartObject;

            /* We remove all objects with a name 
            that begins with "ToRemove". */
            var chartObjectsCopy = Chart.Objects.ToArray();

            foreach (var chartObject in chartObjectsCopy)
            {
                if (chartObject.Name.StartsWith("ToRemove", System.StringComparison.OrdinalIgnoreCase))
                {
                    /* Chart 'RemoveObject' gets the object name
                    as a parameter. */
                    Chart.RemoveObject(chartObject.Name);
                }

            }
        }

        public override void Calculate(int index)
        {
        }
    }
}

الأحداث

تحتوي كائنات الرسم البياني على العديد من الأحداث التي يمكنك استخدامها لمعرفة الكائنات التي تم رسمها أو تحديثها أو إزالتها:

  • ObjectsAdded - يتم تشغيله عند إضافة كائن رسم بياني واحد أو أكثر إلى الرسم البياني.
  • ObjectsRemoved - يتم تشغيله عند إزالة كائن رسم بياني واحد أو أكثر من الرسم البياني.
  • ObjectsUpdated - يتم تشغيله عند تحديث كائن رسم بياني واحد أو أكثر (تم تغيير إحدى خصائصه بواسطة المستخدم أو المؤشر النشط أو cBot).
  • ObjectsSelectionChanged - يتم تشغيله عند تحديد كائن رسم بياني واحد أو أكثر بواسطة المستخدم.
  • ObjectHoverChanged - يتم تشغيله عندما يحوم مؤشر الماوس فوق كائن رسم بياني.

يستخدم المثال التالي جميع أنواع الأحداث الخمسة:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            Chart.ObjectsAdded += Chart_ObjectsAdded;
            Chart.ObjectsRemoved += Chart_ObjectsRemoved;
            Chart.ObjectsUpdated += Chart_ObjectsUpdated;
            Chart.ObjectsSelectionChanged += Chart_ObjectsSelectionChanged;
            Chart.ObjectHoverChanged += Chart_ObjectHoverChanged;
        }

        private void Chart_ObjectHoverChanged(ChartObjectHoverChangedEventArgs obj) => throw new System.NotImplementedException();

        private void Chart_ObjectsSelectionChanged(ChartObjectsSelectionChangedEventArgs obj) => throw new System.NotImplementedException();

        private void Chart_ObjectsUpdated(ChartObjectsUpdatedEventArgs obj) => throw new System.NotImplementedException();

        private void Chart_ObjectsRemoved(ChartObjectsRemovedEventArgs obj) => throw new System.NotImplementedException();

        private void Chart_ObjectsAdded(ChartObjectsAddedEventArgs obj) => throw new System.NotImplementedException();

        public override void Calculate(int index)
        {
        }
    }
}

الكائنات التفاعلية وغير التفاعلية

عند العمل مع الكائنات التفاعلية، يمكن للمستخدمين تغيير خصائصها مثل موضع الكائن واللون والتعليق وما إلى ذلك. جميع الكائنات المرسومة من قبل المستخدم تكون تفاعلية بشكل افتراضي.

ملاحظة

لا يمكن تغيير خاصية ChartStaticText بغض النظر عما إذا كان الكائن المرتبط بها تفاعليًا أم لا.

لجعل الكائن تفاعليًا، قم بتعيين خاصية IsInteractive إلى true كما هو موضح أدناه:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var verticalLine = Chart.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);

            verticalLine.IsInteractive = true;
        }

        public override void Calculate(int index)
        {
        }
    }
}

تحتوي جميع كائنات الرسم البياني على خاصية IsInteractive. القيمة الافتراضية لها هي false.

إذا كان كائن الرسم البياني تفاعليًا، فلن تتم إزالته عند إزالة مثيل المؤشر أو cBot أو إيقافه. على العكس من ذلك، تتم إزالة الكائنات غير التفاعلية تلقائيًا عند توقف المؤشر أو cBot عن العمل.

لتجنب الفوضى، تأكد من تنظيف الكائنات التفاعلية بعد إزالة المثيل المرتبط بها باستخدام طريقة Destroy للمؤشر أو طريقة OnStop لـ cBot.

إذا لم يكن كائن الرسم البياني تفاعليًا، فسيكون أيضًا غير مرئي في القوائم ومجموعات كائنات الرسم البياني.

الكائنات المقفلة وغير المقفلة

يمنع قفل كائن الرسم البياني المستخدم من تعديله أو تحديثه. يمكنك القيام بذلك عبر مربع خصائص المتداول (خصائص الرسم البياني) أو عن طريق تعيين خاصية IsLocked إلى true. القيمة الافتراضية هي false.

يمكنك استخدام القفل لجعل الكائن تفاعليًا ولكن في نفس الوقت منع المستخدم من تحديثه. يقوم المثال التالي بقفل كائن الخط العمودي:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var verticalLine = Chart.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);

            verticalLine.IsLocked = true;
        }

        public override void Calculate(int index)
        {
        }
    }
}

إظهار وإخفاء

يمكنك رسم كائن على الرسم البياني ثم إخفاؤه لاحقًا. بينما سيظل الكائن موجودًا على الرسم البياني، سيكون غير مرئي تمامًا.

للقيام بذلك، قم بتعيين خاصية IsHidden إلى true.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var verticalLine = Chart.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);

            verticalLine.IsHidden = true;
        }

        public override void Calculate(int index)
        {
        }
    }
}

استخدام الموارد هو الاعتبار الرئيسي لاستخدام هذه الميزة. إذا كان هناك كائن يجب أن يظهر بشكل متكرر على الرسم البياني (ولكن ليس طوال الوقت)، فمن الأفضل إخفاؤه بدلاً من إزالته وإعادة رسمه في كل مرة يكون هناك حاجة إليه.

تحديد الكائن ومؤشر المظهر (ZIndex)

بطبيعة الحال، قد تكون هناك حالات حيث تتقاطع العديد من الكائنات مع بعضها البعض على الرسم البياني، مما يجعل تحديد كائن معين صعبًا أو مستحيلاً تمامًا. سيكون فقط الكائن الذي تم رسمه في النهاية قابلاً للتحديد عند تحريك مؤشر الماوس فوق مجموعة من كائنات الرسم البياني المتقاطعة.

لتغيير هذا السلوك يمكنك استخدام خاصية ZIndex. يمكن أن يكون ذلك مفيدًا عند محاولة عرض أنماط معقدة من كائنات الرسم البياني.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var firstVerticalLine = Chart.DrawVerticalLine("line1", Chart.LastVisibleBarIndex, Color.Red);

            firstVerticalLine.IsInteractive = true;

            var secondVerticalLine = Chart.DrawVerticalLine("line2", Chart.LastVisibleBarIndex, Color.Yellow);

            secondVerticalLine.IsInteractive = true;

            firstVerticalLine.ZIndex = secondVerticalLine.ZIndex + 1;
        }

        public override void Calculate(int index)
        {
        }
    }
}

بمجرد إرفاقه بالرسم البياني، سيعرض المؤشر أعلاه خطًا عموديًا أحمر بدلاً من الأصفر. نظرًا لأن قيمة خاصية ZIndex للخط الأول أعلى من القيمة المقابلة للخط الثاني، فإنه يأخذ الأسبقية على الخط الثاني (الأصفر).

بعبارة أخرى، تحدد خاصية ZIndex أي كائنات الرسم البياني يتم عرضها أولاً عندما تتداخل. يتم تعيين قيمة معينة لخاصية ZIndex تلقائيًا لجميع كائنات الرسم البياني المرسومة.

معرفة ما إذا تمت إزالة كائن

ترث جميع كائنات الرسم البياني خاصية IsAlive من الفئة الأساسية ChartObject. تكون قيمة هذه الخاصية true طالما أن الكائن موجود على الرسم البياني (بغض النظر عما إذا كان مرئيًا أو غير مرئي). يتم تعيين القيمة إلى false بمجرد إزالة الكائن من الرسم البياني.

إذا قمت بحفظ مرجع لكائن رسم بياني وتمت إزالة هذا الكائن بواسطة المستخدم، يمكنك التحقق من خاصية IsAlive للتحقق مما إذا كان الكائن حيًا أو ميتًا.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        private ChartVerticalLine _verticalLine;

        protected override void Initialize()
        {
            _verticalLine = Chart.DrawVerticalLine("line1", Chart.LastVisibleBarIndex, Color.Red);
            _verticalLine.IsInteractive = true;

            Chart.ObjectsRemoved += Chart_ObjectsRemoved;

            Print(_verticalLine.IsAlive);
        }

        private void Chart_ObjectsRemoved(ChartObjectsRemovedEventArgs obj)
        {
            Print(_verticalLine.IsAlive);

            /* If the object is removed, we should rid of its
            reference. Otherwise, it will remain in memory. */
            if (_verticalLine.IsAlive is false)
            {
                _verticalLine = null;

                Print("Object reference removed");
            }
        }

        public override void Calculate(int index)
        {
        }
    }
}

إذا قمت بتشغيل مثيل لهذا المؤشر، انقر بزر الماوس الأيمن على الخط الأحمر وقم بإزالته. يجب أن يعرض السجل بعد ذلك رسالة "Object reference removed".

إذا احتفظت بمرجع لكائن رسم بياني (ميت)، فسيحدث تسرب في الذاكرة. أثناء جمع النفايات، سيظل الكائن الخاص بك يعتبر حيًا، مما يعني أنه سينجو من عملية الجمع.

لتجنب هذه المشكلة، استخدم حدث ObjectsRemoved مع خاصية IsAlive.

مؤشر الشريط أو الوقت

عند برمجة كائنات الرسم البياني، يمكنك استخدام إما وقت الرسم البياني أو مؤشر الشريط للمحور السيني.

في رأينا، وقت الرسم البياني هو الخيار الأفضل. عند استخدام مؤشرات الأشرطة، لا يمكنك التخطيط للقيم المستقبلية (لأن المؤشرات المطلوبة غير موجودة بعد) ولا يمكنك حساب أي مسافات بين الأشرطة. ومع ذلك، قد يكون استخدام مؤشرات الأشرطة أسهل، خاصة في حالة كائنات الرسم البياني البسيطة نسبيًا.

تحتوي جميع طرق Chart.Draw على تحميلات زائدة مختلفة لمؤشرات الأشرطة ووقت الرسم البياني.