ข้ามไปที่เนื้อหา

กรอบเวลาที่กำหนดเอง

API กรอบเวลาที่กำหนดเองมีประเภทที่ช่วยให้คุณสามารถแสดงข้อมูล OHLC ที่กำหนดเองจากแหล่งข้อมูลใดๆ รวมถึง API ของบุคคลที่สาม การคำนวณสังเคราะห์ หรือไฟล์ในเครื่อง โดยตรงในกราฟ cTrader เอนทิตี API เช่น CustomTimeFrame และ TimeFrameManager ช่วยให้คุณสามารถสตรีมแท่งเทียนจากแหล่งข้อมูลเฉพาะและแสดงในcTrader เป็นกรอบเวลาที่สมบูรณ์

ประเภทที่สำคัญ ได้แก่:

  • TimeFrameManager.Custom.Add(name) เพื่อลงทะเบียนกรอบเวลาที่กำหนดเองใหม่ด้วยชื่อที่ผู้ใช้กำหนด
  • CustomTimeFrame.BarsNeeded เพื่อกำหนดวิธีและเวลาที่โหลดข้อมูลสำหรับกราฟ
  • CustomBars.AppendBars(), CustomBars.UpdateLastBar(), CustomBars.PrependBars() เพื่อจัดการชุดข้อมูลแบบไดนามิก โดยแต่ละ CustomBar มีหกฟิลด์เหล่านี้: time, open, high, low, close และ volume

เมื่อเพิ่มแล้ว กรอบเวลาที่กำหนดเองจะรวมเข้ากับ UI กรอบเวลา ของ cTrader อย่างราบรื่นและปรากฏในเมนูแบบเลื่อนลงพร้อมกับกรอบเวลาในตัว ผู้ใช้สามารถสลับระหว่างกรอบเวลามาตรฐานและกรอบเวลาที่กำหนดเองได้อย่างง่ายดาย

เคล็ดลับ

ใช้กรอบเวลาที่กำหนดเองเพื่อแสดงตลาดภายนอก จำลองประเภทแท่งเทียนทดลอง สร้างกราฟสหสัมพันธ์/อาร์บิทราจขั้นสูง หรือทดสอบย้อนหลังกลยุทธ์บนข้อมูลเฉพาะ

วัตถุ API กรอบเวลาที่กำหนดเองสามารถใช้เพื่อทำสิ่งต่อไปนี้:

ฟีเจอร์หรือการดำเนินการ ตัวอย่าง
แสดงข้อมูลตลาดทางเลือก โหลดแท่งเทียนจาก REST API (เช่น AlphaVantage)
แสดงราคานอกแพลตฟอร์ม
จำลองประเภทแท่งเทียนสังเคราะห์ สร้างแท่งเทียน Heikin-Ashi, Renko หรือแท่งเทียนตามปริมาณ
สร้างแท่งเทียนจากดัชนีความรู้สึกหรือดัชนีเศรษฐกิจ
ทดสอบข้อมูลออฟไลน์ โหลดแท่งเทียนที่กำหนดเองจากไฟล์ CSV หรือ JSON
ทดสอบย้อนหลังบนชุดข้อมูลเฉพาะ
การซ้อนทับกลยุทธ์ข้ามสินทรัพย์ พล็อต GBP/USD บนกราฟ EUR/USD
พัฒนาโมเดลอาร์บิทราจ
การควบคุม UI ที่เพิ่มขึ้น สลับ ทำเป็นรายการโปรด หรือแก้ไขกรอบเวลาที่กำหนดเอง

สร้างกรอบเวลาที่กำหนดเองตามข้อมูลที่มีอยู่

ปลั๊กอินนี้แสดงวิธีสร้างและแสดงกรอบเวลาภายในวันสังเคราะห์ใน cTrader

  • ปลั๊กอินสร้างกรอบเวลา 25 นาทีโดยดึงแท่งเทียน 1 นาทีดั้งเดิมสำหรับสัญลักษณ์ที่ใช้งานอยู่ รวมเป็นแท่งเทียน 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 โดยใช้ออบเจ็กต์ API กรอบเวลาที่กำหนดเอง

  • ปลั๊กอินสร้างช่วงเวลาที่กำหนดเองใน cTrader โดยการดึงข้อมูล OHLC รายวันย้อนหลังสำหรับ IBM จาก API ของ 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
        }
    }
}