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

الأطر الزمنية المخصصة

توفر واجهة برمجة التطبيقات للإطار الزمني المخصص أنواعًا تمكنك من عرض بيانات OHLC المخصصة من أي مصدر، بما في ذلك واجهات برمجة التطبيقات الخارجية، والحسابات الاصطناعية أو الملفات المحلية، مباشرة في مخططات cTrader. تسمح لك كيانات واجهة برمجة التطبيقات، مثل CustomTimeFrame وTimeFrameManager، ببث الشموع من مصدر بيانات محدد وعرضها في cTrader كفترة كاملة.

تشمل الأنواع المهمة:

  • TimeFrameManager.Custom.Add(name) لتسجيل فترة مخصصة جديدة باسم يحدده المستخدم.
  • CustomTimeFrame.BarsNeeded لتحديد كيفية ووقت تحميل البيانات للمخطط.
  • CustomBars.AppendBars()، CustomBars.UpdateLastBar()، CustomBars.PrependBars() لإدارة السلسلة بشكل ديناميكي، حيث تحتوي كل CustomBar على هذه الحقول الستة: time، open، high، low، close وvolume.

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

نصيحة

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

يمكن استخدام كائنات واجهة برمجة التطبيقات للإطار الزمني المخصص للقيام بما يلي:

الميزة أو العملية أمثلة
عرض بيانات السوق البديلة تحميل الشموع من واجهات برمجة التطبيقات REST (مثل AlphaVantage)
تصور الأسعار خارج المنصة
محاكاة أنواع الشموع الاصطناعية إنشاء شموع Heikin-Ashi أو Renko أو شموع الحجم
إنشاء شموع من مؤشرات المشاعر أو المؤشرات الاقتصادية
اختبار البيانات غير المتصلة تحميل الشموع المخصصة من ملف CSV أو JSON
الاختبار العكسي على مجموعات البيانات الخاصة
تراكبات استراتيجية الأصول المتعددة رسم GBP/USD على مخططات EUR/USD
تطوير نماذج المراجحة
تحكم محسن في واجهة المستخدم تبديل أو تفضيل أو تعديل الفترات المخصصة

إنشاء فترة مخصصة بناءً على البيانات الموجودة

توضح الإضافة هنا كيفية إنشاء وعرض فترة زمنية اصطناعية داخل اليوم في cTrader.

  • تقوم الإضافة ببناء إطار زمني مدته 25 دقيقة عن طريق جلب شموع الدقيقة الواحدة الأصلية للرمز النشط، وتجميعها في شموع OHLC مدتها 25 دقيقة ثم بث النتيجة في سلسلة CustomBar.
  • يظهر الإطار الزمني الجديد في القائمة المنسدلة لاختيار الأطر الزمنية باسم 25Min.
  • عندما يقوم المستخدمون بالتمرير للخلف على المخطط، تقوم الإضافة تلقائيًا بتحميل المزيد من بيانات الدقائق، وإضافة شموع 25 دقيقة أقدم في البداية والحفاظ على تحديث العرض.
  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
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
using System;
using System.Linq;                 
using cAlgo.API;
using cAlgo.API.Internals;

namespace cAlgo.Plugins
{
    [Plugin(AccessRights = AccessRights.None)]
    public class TF25 : Plugin
    {
        private CustomTimeFrame _tf25Min;
        private bool _isLoadMoreEnabled = true;

        protected override void OnStart()
        {
            // Create the 25-minute TF
            _tf25Min = TimeFrameManager.Custom.Add("25Min");
            _tf25Min.Description = "25‑minute aggregated from 1‑minute bars";

            // Hook initial load and on‑scroll‑back
            _tf25Min.NewChart += OnNewChart;
            _tf25Min.BarsNeeded = OnBarsNeeded;
        }

        private void OnNewChart(CustomTimeFrameNewChartEventArgs args)
        {
            var cb    = args.CustomBars;
            var chart = args.Chart;

            // Show a loading indicator
            var loading = new TextBlock { Text = "Loading 25‑min bars…", FontSize = 12 };
            chart.AddControl(loading);

            // Fetch the 1‑min bars and aggregate
            MarketData.GetBarsAsync(TimeFrame.Minute, cb.Symbol.Name, minuteBars =>
            {
                var aggregated = minuteBars
                    .Select((bar, idx) => new { bar, idx })
                    .GroupBy(x => x.idx / 25)
                    .Select(g =>
                    {
                        var first = g.First().bar;
                        var last  = g.Last().bar;
                        return new CustomBar(
                            time:        first.OpenTime,
                            open:        first.Open,
                            high:        g.Max(x => x.bar.High),
                            low:         g.Min(x => x.bar.Low),
                            close:       last.Close,
                            volume:  g.Sum(x => (int)x.bar.TickVolume)
                        );
                    });

                chart.RemoveControl(loading);


            });
        }

        private void OnBarsNeeded(CustomTimeFrameBarsNeededArgs args)
        {
            var cb = args.CustomBars;

            // Same logic for explicit BarsNeeded triggers
            MarketData.GetBarsAsync(TimeFrame.Minute, cb.Symbol.Name, minuteBars =>
            {
                var aggregated = minuteBars
                    .Select((bar, idx) => new { bar, idx })
                    .GroupBy(x => x.idx / 25)
                    .Select(g => new CustomBar(
                        time:        g.First().bar.OpenTime,
                        open:        g.First().bar.Open,
                        high:        g.Max(x => x.bar.High),
                        low:         g.Min(x => x.bar.Low),
                        close:       g.Last().bar.Close,
                        volume:  g.Sum(x => (int)x.bar.TickVolume)
                    ));
                cb.AppendBars(aggregated);
                 args.CustomBars.NeedsMore += _ =>
                {
                    if (!_isLoadMoreEnabled)
                    {
                        Print("Load‑more disabled; skipping additional bars.");
                        return;
                    }

                    Print("NeedsMore fired; loading more history…");
                    minuteBars.LoadMoreHistoryAsync(loadArgs =>
                    {
                        Print($"Loaded {loadArgs.Count} more 1‑min bars");
                        if (loadArgs.Count == 0)
                            return;

                        Sleep(TimeSpan.FromSeconds(1));
                        args.CustomBars.PrependBars(minuteBars.Take(loadArgs.Count).Select(bar => new CustomBar(bar.OpenTime, bar.Open, bar.High, bar.Low, bar.Close, (int)bar.TickVolume)));
                    });
                };
            });
        }

        protected override void OnStop()
        {
        }
    }
}

إنشاء فترة مخصصة باستخدام بيانات خارجية

توضح الإضافة هنا كيفية جلب وعرض البيانات المالية الخارجية في مخططات cTrader باستخدام كائنات واجهة برمجة التطبيقات للإطار الزمني المخصص.

  • تقوم الإضافة بإنشاء فترة مخصصة في cTrader عن طريق استرجاع بيانات OHLC اليومية التاريخية لشركة IBM من واجهة برمجة تطبيقات AlphaVantage.
  • تقوم بتحليل استجابة CSV وتحميل البيانات في سلسلة CustomBar، والتي يتم عرضها بعد ذلك كفترة مخصصة قابلة للاختيار تسمى AlphaVantage في واجهة مستخدم المخطط.
 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
61
62
63
64
65
66
67
68
69
70
71
72
using System;
using System.Collections.Generic;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Plugins
{
    [Plugin(AccessRights = AccessRights.None)]
    public class CustomTimeFrameAlphaVantage : Plugin
    {
        private const string ApiKey = "YOUR_ALPHA_VANTAGE_KEY";
        private const string Symbol = "IBM";
        private const string Endpoint = $"https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol={Symbol}&apikey={ApiKey}&datatype=csv&outputsize=full";

        private CustomTimeFrame _customTimeFrame;

        protected override void OnStart()
        {
            _customTimeFrame = TimeFrameManager.Custom.Add("AlphaVantage");

            _customTimeFrame.Description = "Loads data from AlphaVantage";

            _customTimeFrame.BarsNeeded = args => 
            {
                var response = Http.Get(new Uri(Endpoint));

                if (!response.IsSuccessful)
                {
                    Print($"Error loading data from AlphaVantage, status code: {response.StatusCode}, body: {response.Body}");
                    return;
                }

                Print($"Response Received: {response.StatusCode}");

                var ohlcData = response.Body.Split(Environment.NewLine)[1..];

                Array.Reverse(ohlcData);

                Print($"ohlcData Count: {ohlcData.Length}");

                var bars = new List<CustomBar>();

                foreach (var ohlc in ohlcData)
                {
                    var ohlcSplit = ohlc.Split(',');

                    if (ohlcSplit.Length < 6) continue;

                    var time = DateTime.Parse(ohlcSplit[0]);
                    var open = double.Parse(ohlcSplit[1]);
                    var high = double.Parse(ohlcSplit[2]);
                    var low = double.Parse(ohlcSplit[3]);
                    var close = double.Parse(ohlcSplit[4]);
                    var volume = long.Parse(ohlcSplit[5]);

                    bars.Add(new CustomBar(time, open, high, low, close, volume));
                }

                Print($"AppendBars Count: {bars.Count}");

                args.CustomBars.AppendBars(bars);
            };
        }

        protected override void OnStop()
        {
            // Handle Plugin stop here
        }
    }
}